Skip to content

Template Method Design Pattern (Behavioral)

Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.


Imagine you’re creating a data mining application that analyzes corporate documents. Users feed the app documents in various formats (PDF, DOC, CSV), and it tries to extract meaningful data from these files in a uniform format.

The first version of the app could work only with DOC files. In the second version, it could support CSV files. A month later, you β€œtaught” it to extract data from PDF files.

At some point, you noticed that all three classes have a lot of similar code. While the code for dealing with various data formats was entirely different in all classes, the code for data processing and analysis was almost identical. Wouldn’t it be great to get rid of the code duplication, leaving the algorithm structure intact?.

The Template Method pattern suggests that you break down an algorithm into a series of steps, turn these steps into methods, and put a series of calls to these methods inside a single template method. The steps may either be abstract, or have some default implementation.

To use the algorithm, the client is supposed to provide its own subclass, implement all abstract steps, and override some of the optional ones if needed (but not the template method itself).

The template method approach can be used in mass housing construction. An architectural plan for building a standard house may contain several extension points that let a potential owner adjust some details of the resulting house.

Each building step, such as laying the foundation, framing, and building walls, remains the same. However, the builders can change the plumbing, the wiring, or the paint of the walls to make the house slightly different from others.


  1. Abstract Class declares methods that act as steps of an algorithm, as well as the actual template method which calls these steps in a specific order.
  2. Concrete Classes can override all of the steps, but not the template method itself.
classDiagram
    class AbstractClass {
        ...
        +templateMethod()
        +step1()
        +step2()* 
        +step3()*
        +hook1()
    }
    class ConcreteClass1 {
        +step2()
        +step3()
    }
    class ConcreteClass2 {
        +step2()
        +step3()
        +hook1()
    }

    AbstractClass <|-- ConcreteClass1
    AbstractClass <|-- ConcreteClass2

# The abstract class defines a template method that contains a
# skeleton of some algorithm.
class GameAI:
# The template method defines the skeleton of an algorithm.
method turn():
collectResources()
buildStructures()
buildUnits()
attack()
# Some of the steps may be implemented right in a base class.
method collectResources():
foreach (s in structures):
s.collect()
# And some of them may be defined as abstract.
abstract method buildStructures()
abstract method buildUnits()
method attack():
enemy = closestEnemy()
if (enemy == null):
sendScouts(map.center)
else:
sendWarriors(enemy.position)
# Concrete classes provide implementation for abstract steps.
class OrcsAI extends GameAI:
method buildStructures():
if (resources > 100):
build("OrcHut")
method buildUnits():
if (resources > 50):
addUnitToQueue("Grunt")
class MonstersAI extends GameAI:
method buildStructures():
# Monsters don't build structures.
method buildUnits():
# Monsters don't build units.

  • Varying specific steps: Use the Template Method pattern when you want to let clients extend only particular steps of an algorithm, but not the whole algorithm or its structure.
  • Eliminating code duplication: Use the pattern when you have several classes that contain almost identical algorithms with some minor differences.
  1. Analyze the target algorithm to see if you can break it into steps.
  2. Create the abstract base class and declare the template method and a set of abstract methods representing the algorithm’s steps.
  3. It’s okay if some steps have a default implementation.
  4. Think about adding hooks between the crucial steps of the algorithm.
  5. For each variation of the algorithm, create a new concrete subclass.

Pros:

  • You can let clients override only certain parts of a large algorithm, making them less affected by changes that happen to other parts.
  • You can pull the duplicate code into a superclass.

Cons:

  • Some clients may be limited by the provided skeleton of an algorithm.
  • You might violate the Liskov Substitution Principle by suppressing a default step implementation via a subclass.
  • Template methods tend to be harder to maintain the more steps they have.
  • Factory Method is a specialization of Template Method. At the same time, a Factory Method may serve as a step in a large Template Method.
  • Template Method is based on inheritance: it lets you alter parts of an algorithm by extending those parts in subclasses. Strategy is based on composition: you can alter parts of the object’s behavior by supplying it with different strategies that correspond to that behavior.

// Template
public abstract class DataProcessor
{
public void Process()
{
ReadData();
ProcessData();
SaveData();
}
protected abstract void ReadData();
protected abstract void ProcessData();
protected abstract void SaveData();
}
// Concrete Implementations
public class CsvProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Read CSV");
protected override void ProcessData() => Console.WriteLine("Process CSV");
protected override void SaveData() => Console.WriteLine("Save CSV");
}
public class JsonProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Read JSON");
protected override void ProcessData() => Console.WriteLine("Process JSON");
protected override void SaveData() => Console.WriteLine("Save JSON");
}
// Usage
class Program
{
static void Main()
{
DataProcessor csv = new CsvProcessor();
csv.Process();
DataProcessor json = new JsonProcessor();
json.Process();
}
}