Patterns. The Template Method pattern

The Template Method pattern (scheme implementation)

1. General information. Purpose. Participants of the pattern

The Template Method pattern refers to patterns in the behavior of classes. A template method specifies the steps of an algorithm and allows subclasses to define some of those steps. In this case, the structure of the algorithm itself does not change.

The essence of the template is that they are placed in some abstract class:

  • methods (operations) describing the algorithm. These methods are called template methods. In their body, they access methods implemented in inherited classes;
  • methods that are replaced in inherited classes. These methods define the desired behavior.

The structure (class diagram) of the Template Method pattern is shown in Figure 1.

The "Template Method" pattern. Class diagram

Figure 1. Structure (class diagram) of the Template Method pattern

The participants of the pattern are the following elements (see Figure 1).

  1. AbstractClass – an abstract class that defines:
  • a list of primitive methods (operations) replaced in specific subclasses;
  • one or more template methods that define the steps (basis) of the algorithm. A template method calls primitive methods implemented in AbstractClass or other objects.
  1. ConcreteClass – concrete class. Implements primitive methods (operations) that perform algorithm steps. The implementation of each step is determined by the characteristics of the subclass.

 

2. Use cases

The Template Method pattern can be used in the following cases:

  • when you need to implement constant steps of the algorithm, each of which (steps) changes depending on the implementation in subclasses;
  • when in one class it is necessary to highlight behavior common to all subclasses in order to avoid code duplication. With this approach, first, differences in the code are highlighted, and then these differences are implemented in inherited classes;
  • when there is a need to call so-called hook operations at certain points.

 

3. An example of implementing a pattern structure in C++

The following code in C++ implements the Template Method pattern.

#include <iostream>
using namespace std;

// Template Method pattern - implementation of the scheme
class AbstractClass abstract
{
public:
  // Template method - calls methods
  // PrimitiveOperation1(), PrimitiveOperation2()
  void TemplateMethod()
  {
    // implementation of calling algorithm
    PrimitiveOperation1();
    PrimitiveOperation2();
  }

  virtual void PrimitiveOperation1() = 0;
  virtual void PrimitiveOperation2() = 0;
};

class ConcreteClass : public AbstractClass
{
public:
  // Specific implementations of operations
  void PrimitiveOperation1()
  {
    cout << "ConcreteClass::PrimitiveOperation1()" << endl;
  }

  void PrimitiveOperation2()
  {
    cout << "ConcreteClass::PrimitiveOperation2()" << endl;
  }
};

int main()
{
  // Create an instance of a specific class
  AbstractClass* p = new ConcreteClass();

  // Call the template method
  p->TemplateMethod();

  // Free up memory
  if (p)
    delete p;
}

 

4. Results

For the Template Method pattern, the following results can be distinguished.

  1. The pattern allows you to move general behavior into library classes.
  2. The code structure in the pattern is inverted. This means that the base class calls the methods of the subclass, and not vice versa.

Methods called from the base class can be of the following types (see Figure 1):

  • specific methods (operations). These are methods called from client classes or ConcreteClass. In Figure 1, these classes are: PrimitiveOperation1() and PrimitiveOperation2();
  • specific methods from the AbstractClass. These are methods that are shared between all subclasses. In Figure 1, such a method is TemplateMethod();
  • primitive (abstract) methods;
  • factory methods. More details about factory methods can be found here (Factory Method pattern);
  • hooks methods (hooks operations). These are methods that implement default behavior that can be changed in inherited classes. It is important that the pattern must clearly separate hook operations from abstract operations. Hook operations may or may not be overridden. Abstract operations must be overridden.

 

5. Hook operation. Example in C++

 

// The Template Method pattern
// An example of a hook operation
// Base class - implements the default method
class BaseClass
{
public:
  // the default method doesn't do any work
  void HookOperation()
  { }

  // Template method
  void Operation()
  {
    // Behavior of the parent class ParentClass
    HookOperation();
  }
};

// Inherited class – does a substitution operation
// HookOperation() of a base class
class DerivedClass : public BaseClass
{
public:
  // Here's an extension of the behavior
  void HookOperation()
  {
    // performing actions that extend a base class method
    // ...
  }
};

 

6. Features of the implementation

For the Template Method pattern, the following implementation features can be distinguished.

  1. Providing access control. In this case, primitive methods called by a template method can be declared in the protected section. This makes it possible to call these methods only in a template manner. Also, primitive methods must be replaced and are declared as purely virtual functions.
  2. Reducing the number of simple ways for the client. Primitive methods (operations) are replaced in subclasses. It is advisable to minimize the number of primitive methods for the client if possible.
  3. Name coordination. This means setting an additional prefix to the names of the methods that need to be replaced.