Behavioral

Template Method

Purpose

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.

UML

           

Behavior

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.

Example

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

Usage

/* 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" ); 
}

Notes