Template Method Pattern

Template Method Pattern

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.

Intent

The Template Method defines the fixed algorithm skeleton in an abstract base class. Specific steps that vary across implementations are declared as abstract methods (or overridable hooks) and implemented by subclasses. The abstract class calls the hooks; subclasses fill them in. The algorithm's overall structure never changes — only the variable steps differ between subclasses. This is an inheritance-based counterpart to Strategy-Pattern: Template Method locks variation at compile time via subclassing, while Strategy swaps it at runtime via composition.

When NOT to Use

  • The algorithm varies in too many ways — each variation requires a new subclass, leading to subclass proliferation that becomes unmanageable
  • The variation is runtime-determined — use Strategy-Pattern with composition instead; Strategy allows swapping behaviour without inheritance
  • The template method would be the only method in the abstract class — if there is nothing else shared, prefer a Strategy interface; the abstract class overhead is not justified
  • Subclasses must override the template method itself to control flow — if this is required, the abstraction is wrong

When to Use

  • Multiple classes share the same algorithm structure with varying implementation steps
  • A single abstract class should enforce an invariant algorithm sequence — the sequence must not be re-ordered by subclasses
  • The Hollywood Principle is the desired design ("don't call us, we'll call you") — the abstract class drives the flow and calls into subclass hooks

How It Works

Participants: AbstractClass (defines templateMethod() with the fixed algorithm skeleton — calls step1(), step2(), etc.; steps may be abstract or provide default hook implementations), ConcreteClass (overrides specific steps to provide variant behaviour).

The template method calls the hook methods; subclasses implement the hooks. Hooks can be optional (default no-op implementation in AbstractClass) or required (declared abstract — subclass must implement). The control flow is inverted — AbstractClass calls ConcreteClass, not the other way around. In Java, the template method is typically declared final to prevent subclasses from overriding the skeleton itself.

Class Diagram

classDiagram
    class AbstractClass {
        <<abstract>>
        +templateMethod()
        +step1()*
        +step2()*
        +hook() : optional
    }
    class ConcreteClassA {
        +step1()
        +step2()
    }
    class ConcreteClassB {
        +step1()
        +step2()
        +hook()
    }
    AbstractClass <|-- ConcreteClassA
    AbstractClass <|-- ConcreteClassB

    note for AbstractClass "templateMethod() defines the\nalgorithm skeleton — calls step1(),\nstep2(), hook() in fixed order.\nSubclasses override steps, not flow."

TypeScript Example

// Template Method — TypeScript
// Source: GoF Design Patterns, p.325
 
abstract class DataProcessor {
  // Template method — the fixed algorithm skeleton
  process(): void {
    this.readData();
    this.processData();
    this.writeData();
    // Hollywood Principle: AbstractClass calls the hook steps — subclass does not call process()
  }
 
  abstract readData(): void;    // required hook — subclass must implement
  abstract processData(): void; // required hook — subclass must implement
 
  writeData(): void {           // optional hook — default implementation provided
    console.log("Writing processed data...");
  }
}
 
class CSVDataProcessor extends DataProcessor {
  readData()    { console.log("Reading CSV file"); }
  processData() { console.log("Parsing CSV rows"); }
}
 
class JSONDataProcessor extends DataProcessor {
  readData()    { console.log("Reading JSON file"); }
  processData() { console.log("Deserialising JSON"); }
}
 
const csv = new CSVDataProcessor();
csv.process(); // AbstractClass drives: readData → processData → writeData

Java Example

// Template Method — Java
// Source: GoF Design Patterns, p.325
 
abstract class DataProcessor {
    // final prevents subclasses from overriding the skeleton
    public final void process() {
        readData();
        processData();
        writeData();
    }
 
    protected abstract void readData();
    protected abstract void processData();
 
    protected void writeData() {
        System.out.println("Writing processed data...");
    }
}
 
class CSVDataProcessor extends DataProcessor {
    protected void readData()    { System.out.println("Reading CSV file"); }
    protected void processData() { System.out.println("Parsing CSV rows"); }
}
 
class JSONDataProcessor extends DataProcessor {
    protected void readData()    { System.out.println("Reading JSON file"); }
    protected void processData() { System.out.println("Deserialising JSON"); }
}
PatternRelationship
Strategy-PatternTemplate Method uses inheritance to vary algorithm steps; Strategy uses composition — both vary an algorithm, but Template Method locks the structure at compile time, Strategy swaps it at runtime
Factory-Method-PatternFactory Method is often a hook step inside a Template Method — the template method calls createProduct() which is a Factory Method
Hook methodsOptional steps with default (no-op) implementations in AbstractClass — a refinement within the Template Method pattern

Sources

  • Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, p.325

Notes that link here: GoF-Patterns-MOC