The Template Method pattern is based on a member function that defines an abstract/default algorithm that subclasses override to provide their concrete/specialized behavior. The template method may define an algorithm's steps and order, while subclasses vary those steps accordingly.
The client creates object of the ConcreteClass which inherits the public interface of AbstractClass. ConcreteClass depends on AbstractClass to implement the invariant steps of the algorithm, while the ConcreteClass implements the primitive steps of the algorithm.
This example applies the Template Method to error logging. CLogger is the abstract class with the Template Method that defines the steps (primitives) of logging an error. The derived classes override the primitives to customize logging the error; CEventLog logs the error to the EventLog, whereas, CDataBaseLog logs the error to the database
/* Abstract class that implements a template method defining the skeletal algorithm.
In this example, the Template Method, LogError(string), uses the primitive operation log() to
log the given message into a specific destination. While the primitive
operation log() has no implementation in the base class, it is implemented appropriately in derived classes,
to log into EventLog, into database,
into text file, etc... */
class CLogger
{
public:
// Template method. Defines logging procedure
(calls polymorphic log() )
void LogError( const std::string &str)
{
// Zero, one or
more invariant steps of logging errors come here.
// ...
// This is the
primitive that can be specialized by subclasses
log ( str );
// Zero, one or
more invariant steps of logging errors come here
// ...
}
private:
// The primitive operations. Default
reports into std output
virtual void log( const std::string &str)
{
// Default is to display into std output
std::cout << "Error description: " << str << std::cout;
}
};
/* Concrete class that implements primitive operations to carry specialized steps of the algorithm (logging error information).
In this example, the primitive operation is log(). It logs information into the event log */
class CEventLog : public CLogger
{
private:
// Primitive method specialized to log into the event log
void log( const std::string & str)
{
std::cout << "Entered CEventLog::log" << std::endl;
// Log string into the NT/W2K event log using ::RegisterEventSource,
//ReportEventLog, etc.
// Logging code using the above APIs comes here
return;
}
};
/* Another concrete class that implements primitive operations to carry specialized
steps of the algorithm (logging error information) In this example, the primitive operation is log(). It logs information into the
the database */
class CDataBaseLog : public CLogger
{
private:
void log( const std::string& str)
{
std::cout << "Entered CDataBaseLog::log" << std::endl;
// log string into database. Use
ODBC, or ADO or OLE DB to log into SQL Server
// Logging code using the ODBC, ADO or OLE DB comes here
return;
}
};
// Helpers
void f();
void g();
int main(int argc, char* argv[])
{
f(); //
log error uses CEventLog
g(); //
log error uses CDatabaseLog
return 0;
}
// Uses CEventLog to log an error message into the event log
void f()
{
/* Note how CEventLog object uses the Template method from the base
class
which calls the polymorphic CEventLog::log() */
CEventLog event;
event.LogError( "Some error message" );
}
// Uses CDataBaseLog to log an error message into the the database
void g()
{
/* Note how CDataBaseLog object uses the Template method from the base
class
which calls the polymorphic CDataBaseLog::log() */
CDataBaseLog event;
event.LogError( "Some error message" );
}
void CEventLog::log( const std::string& str)
{
// call base operation first
CLogger::log( str );
// Log string into the NT/W2K event log using
::RegisterEventSource,
//ReportEventLog, etc.
// Logging code using the above APIs comes here
return;
}