Chapter 05 · Article 25 of 55

Template Method Pattern

Type: Behavioural Design Pattern Also Known As: Hot Spot Pattern Complexity: Popularity:

Article outline14 sections on this page

Overview

Type: Behavioural Design Pattern
Also Known As: Hot Spot Pattern
Complexity: ***
Popularity:

Intent

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

The pattern encapsulates the invariant parts of an algorithm in a base class while leaving the variable parts to be implemented by derived classes. The template method itself is typically declared final (or sealed) to prevent subclasses from altering the algorithm's sequence - only the individual steps can be overridden.

Motivation

Consider a scenario where multiple classes perform similar operations following the same high-level sequence but differ in specific low-level details. Without Template Method, each class duplicates the algorithm's skeleton, leading to maintenance nightmares and inconsistency. The pattern extracts the common structure into a single location, enforcing consistency while preserving flexibility.


Problem It Solves

  1. Code Duplication in Similar Algorithms - When several classes implement variations of the same algorithm, the shared logic gets copy-pasted across all implementations. Any bug fix or enhancement must be replicated everywhere.

  2. Enforcing Algorithm Structure - Without a fixed skeleton, subclasses might accidentally skip steps, reorder them, or introduce inconsistencies. Template Method guarantees the sequence is always followed.

  3. Uncontrolled Extension Points - Frameworks need to let users customize behaviour at specific points without giving them the ability to break the overall workflow. Template Method provides controlled "hot spots" for customization.

  4. Violation of the Open/Closed Principle - Modifying existing code to add new variations violates OCP. Template Method allows extension through subclassing without modifying the base algorithm.


When to Use / When NOT to Use

When to UseWhen NOT to Use
Multiple classes share the same algorithm structure but differ in specific stepsThe algorithm varies significantly between implementations with no common skeleton
You want to enforce a fixed sequence of operationsYou need to swap algorithms at runtime (prefer Strategy)
Framework design where users extend behaviour at predefined hook pointsThe number of variations is small and unlikely to grow
You want to apply the Hollywood Principle - base class calls subclass, not vice versaComposition would be simpler and more flexible than inheritance
Common pre/post-processing logic surrounds variable core logicDeep inheritance hierarchies already exist (adding more layers increases fragility)
You need to prevent subclasses from changing the algorithm's orderYou need multiple independent variation axes (prefer Bridge or Decorator)

Key Concepts & Theory

Template Method (Final/Sealed)

The template method defines the algorithm's skeleton as a sequence of steps. It is declared final (Java), sealed (C#), or non-virtual to prevent subclasses from overriding the sequence itself. Only the individual steps are open for customization.

Abstract Steps (Primitive Operations)

These are methods that must be overridden by every concrete subclass. They represent the variable parts of the algorithm that have no sensible default implementation.

Concrete Steps (Invariant Operations)

Steps with fixed implementations in the base class that subclasses cannot override. These represent the invariant parts of the algorithm shared across all variations.

Hook Methods

Optional methods with a default (often empty) implementation in the base class. Subclasses may override them to inject additional behaviour at specific points. Hooks provide optional extension without forcing implementation.

// Hook example  -  subclass can optionally override
protected boolean customerWantsCondiments() {
    return true;  // default: yes
}

The Hollywood Principle

"Don't call us, we'll call you."

The base class (high-level component) calls the subclass methods (low-level components), not the other way around. This inverts the typical control flow - the framework drives execution and calls into user code at the appropriate moments. This principle reduces coupling and prevents "dependency rot" where high-level and low-level components become circularly dependent.


ASCII Class Diagram

┌─────────────────────────────────────┐
│         AbstractClass                │
├─────────────────────────────────────┤
│ + templateMethod() [final]          │──────────────────────────┐
│ # step1()          [abstract]       │                          │
│ # step2()          [abstract]       │   templateMethod() {     │
│ # step3()          [concrete]       │       step1();           │
│ # hook()           [virtual/empty]  │       step2();           │
├─────────────────────────────────────┤       step3();           │
│                                     │       if (hook())        │
└──────────┬──────────────┬───────────┘           step4();      │
           │              │                   }                  │
           │              │               ────────────────────────┘
           ▼              ▼
┌──────────────────┐  ┌──────────────────┐
│  ConcreteClassA  │  │  ConcreteClassB  │
├──────────────────┤  ├──────────────────┤
│ # step1() {...}  │  │ # step1() {...}  │
│ # step2() {...}  │  │ # step2() {...}  │
│ # hook()  {...}  │  │                  │  ← uses default hook
└──────────────────┘  └──────────────────┘

Key relationships:

  • AbstractClass owns the template method and defines the algorithm skeleton
  • ConcreteClassA/B override abstract steps and optionally override hooks
  • The template method is final - subclasses cannot change the call sequence

Pseudocode Implementation

Example 1: Data Mining Framework

abstract class DataMiner {

    // Template method  -  FINAL, cannot be overridden
    final method mine(path: String) {
        file = openFile(path)
        rawData = extractData(file)
        data = parseData(rawData)
        analysis = analyzeData(data)
        sendReport(analysis)
        closeFile(file)
    }

    // Abstract steps  -  MUST be implemented by subclasses
    abstract method openFile(path: String): File
    abstract method extractData(file: File): RawData
    abstract method parseData(raw: RawData): Data

    // Concrete step  -  shared across all subclasses
    method analyzeData(data: Data): Analysis {
        // Common analysis logic: compute averages, find anomalies
        return StandardAnalyzer.analyze(data)
    }

    // Concrete step  -  shared default reporting
    method sendReport(analysis: Analysis) {
        EmailService.send(admin, analysis.summary())
    }

    // Hook  -  subclasses may override
    method closeFile(file: File) {
        file.close()
    }
}

class CSVMiner extends DataMiner {

    method openFile(path: String): File {
        return CSVReader.open(path)
    }

    method extractData(file: File): RawData {
        return file.readAllLines()
    }

    method parseData(raw: RawData): Data {
        rows = []
        for each line in raw:
            rows.add(line.split(","))
        return Data(rows)
    }
}

class PDFMiner extends DataMiner {

    method openFile(path: String): File {
        return PDFLibrary.open(path)
    }

    method extractData(file: File): RawData {
        return file.extractText()  // OCR if needed
    }

    method parseData(raw: RawData): Data {
        return PDFParser.structuredParse(raw)
    }

    // Override hook  -  PDF files need explicit resource release
    method closeFile(file: File) {
        file.releaseResources()
        file.close()
    }
}

// Client code
miner = new CSVMiner()
miner.mine("/data/sales-2026.csv")

miner = new PDFMiner()
miner.mine("/data/report-q1.pdf")

Example 2: Game AI Turn System

abstract class GameAI {

    // Template method
    final method takeTurn() {
        collectResources()
        buildStructures()
        buildUnits()
        attack()
    }

    // Concrete step  -  all AI types collect resources the same way
    method collectResources() {
        for each structure in ownedStructures:
            structure.collect()
    }

    // Abstract steps  -  each AI type has unique strategy
    abstract method buildStructures()
    abstract method buildUnits()

    // Hook with default behaviour
    method attack() {
        // Default: attack nearest enemy
        enemy = findNearestEnemy()
        if (enemy != null)
            sendWarriors(enemy.position)
    }
}

class OrcsAI extends GameAI {

    method buildStructures() {
        if (hasResources()):
            build(Barracks)
            build(Farm)
    }

    method buildUnits() {
        if (hasFreeBarracks()):
            train(Warrior)
    }

    // Override attack  -  orcs are aggressive
    method attack() {
        enemies = findAllEnemies()
        sendAllUnits(enemies.strongest().position)
    }
}

class HumansAI extends GameAI {

    method buildStructures() {
        if (hasResources()):
            build(Castle)
            build(Wall)
    }

    method buildUnits() {
        if (hasFreeBarracks()):
            train(Archer)
            train(Knight)
    }
    // Uses default attack behaviour
}

Template Method vs Strategy

AspectTemplate MethodStrategy
MechanismInheritanceComposition
Binding TimeCompile-time (static)Runtime (dynamic)
GranularityVaries individual steps of an algorithmReplaces the entire algorithm
Algorithm OwnershipBase class owns the skeletonClient or context owns the selection
FlexibilityLimited to subclass hierarchyAny conforming strategy can be injected
Code ReuseShared logic lives in base classEach strategy is self-contained
Number of ClassesOne subclass per variationOne strategy class per variation
Control FlowHollywood Principle (base calls subclass)Client calls strategy directly
CouplingTight (subclass coupled to base class)Loose (interface-based)
TestingHarder (must instantiate concrete subclass)Easier (mock/stub strategies independently)
When to PreferFixed algorithm structure with variable stepsInterchangeable algorithms, runtime switching
Violation RiskFragile Base Class problemStrategy explosion (too many small classes)

Rule of thumb: Use Template Method when the algorithm's structure is invariant and you want to enforce it. Use Strategy when you need runtime flexibility or want to avoid inheritance hierarchies.


Real-World Examples

JUnit Framework - setUp() / tearDown()

JUnit's TestCase class uses Template Method. The runBare() method defines the skeleton: call setUp(), run the test method, call tearDown(). Test authors override setUp() and tearDown() without altering the execution sequence.

Java Servlet - doGet() / doPost()

HttpServlet.service() is the template method that dispatches to doGet(), doPost(), doPut(), etc. based on the HTTP method. Developers override specific handlers without touching the dispatch logic.

React Component Lifecycle

React class components follow Template Method: componentDidMount(), shouldComponentUpdate(), render(), componentWillUnmount() are hooks called by React's reconciliation algorithm. Developers override specific lifecycle methods; React controls the invocation order.

Build Systems (Maven Lifecycle)

Maven's build lifecycle (validate → compile → test → package → install → deploy) is a template method. Plugins bind to specific phases (steps) without altering the overall build sequence.

Java's AbstractList / AbstractMap

These abstract classes implement most List/Map operations in terms of a few abstract methods (get(), size()). Subclasses only implement the primitives; the template handles iteration, equality, hashing, etc.


Advantages & Disadvantages

AdvantagesDisadvantages
Eliminates code duplication by extracting common algorithm into base classTight coupling between base and subclasses via inheritance
Enforces a consistent algorithm structure across all variationsFragile Base Class problem - changes to base can break subclasses
Follows Open/Closed Principle - extend via subclassing, not modificationCan lead to deep inheritance hierarchies
Provides controlled extension points (hooks) for optional customizationSubclasses may be confused about which methods to override
Implements Hollywood Principle - reduces dependency rotHarder to understand control flow (inverted via callbacks)
Easy to add new variations without modifying existing codeLimited to single inheritance in languages without mixins
Simplifies client code - just instantiate the right subclassToo many abstract methods make subclassing burdensome
Natural fit for framework designRuntime algorithm switching is impossible without restructuring

Constraints & Edge Cases

Fragile Base Class Problem

Modifying the template method or adding new steps in the base class can silently break all existing subclasses. Mitigation: keep the template method stable, version it carefully, and document the contract thoroughly.

Too Many Abstract Methods

If the base class declares too many abstract steps, subclasses become burdensome to implement. Every new subclass must provide implementations for all abstract methods, even if some are trivial. Mitigation: provide sensible defaults (make them hooks instead of abstract methods) and only force overriding where truly necessary.

Hook Abuse

Hooks with empty default implementations can be misused to inject arbitrary behaviour that violates the algorithm's intent. Subclasses might use hooks to skip steps or introduce side effects. Mitigation: document hook contracts clearly and validate post-conditions in the template method.

Liskov Substitution Principle (LSP) Concerns

Subclass step implementations must honour the base class's contract. If parseData() is expected to return non-null structured data, a subclass returning null violates LSP and breaks the template method's subsequent steps. Mitigation: use assertions/contracts in the template method to validate step outputs.

Thread Safety

If the template method uses shared mutable state, concurrent execution by multiple threads can cause race conditions. Each step might assume exclusive access. Mitigation: make template methods stateless or synchronize appropriately.

Diamond Inheritance (Multiple Inheritance Languages)

In C++ or Python, multiple inheritance can create ambiguity about which base class's template method or step implementation to use. Mitigation: use virtual inheritance or prefer composition.


Interview Follow-ups

Q1: How does Template Method differ from Factory Method?

Answer: Factory Method is actually a specialization of Template Method. In Factory Method, the "step" being deferred to subclasses is specifically object creation. Template Method is the general pattern - any algorithmic step can be deferred. Factory Method focuses on what to create; Template Method focuses on how to execute an algorithm.

Q2: Can you combine Template Method with other patterns?

Answer: Yes, commonly combined with:

  • Factory Method - a step in the template creates objects via Factory Method
  • Strategy - individual steps delegate to strategy objects for runtime flexibility (hybrid approach)
  • Observer - hooks notify observers at specific algorithm points
  • Decorator - wrap the template method to add cross-cutting concerns (logging, timing)

Q3: How would you refactor a Template Method to use composition instead?

Answer: Replace inheritance with a configuration object containing function references (lambdas/callbacks) for each variable step. The former base class accepts this configuration and calls the functions at appropriate points. This transforms Template Method into a Strategy-like approach, gaining runtime flexibility at the cost of losing the enforced type contract that abstract methods provide.


Hints-Only Questions

H1: "Design a report generation system where PDF, HTML, and Excel reports share the same generation pipeline but differ in rendering."

Hints:

  • Think about what steps are common (fetch data, validate, format headers, render body, add footer) vs. what varies (rendering)
  • Consider which steps should be abstract vs. hooks - does every format need custom header logic?

H2: "You have a legacy system with 12 subclasses of a template method. A new requirement needs a step inserted between step 2 and step 3. How do you handle this?"

Hints:

  • Consider backward compatibility - can the new step be a hook with a no-op default?
  • Think about the Fragile Base Class problem and how to test all 12 subclasses after the change

Counter Questions to Ask Interviewer

  1. "Is the algorithm's structure truly fixed, or might the sequence of steps need to vary between implementations?" - Determines if Template Method is appropriate or if Strategy/Chain of Responsibility fits better.

  2. "How many variations do we expect, and will they grow over time?" - A small, stable set might not justify the pattern's overhead; a growing set validates it.

  3. "Are there multiple independent axes of variation?" - If yes, Template Method alone leads to class explosion; Bridge or composition might be needed.

  4. "Do we need to switch behaviour at runtime?" - Template Method binds at compile-time via inheritance; runtime switching requires Strategy or a hybrid.

  5. "What's the team's comfort level with inheritance hierarchies?" - Deep hierarchies are harder to maintain; if the team prefers composition, a different approach may be more sustainable.


References & Whitepapers

  1. Gamma, E., Helm, R., Johnson, R., Vlissides, J. - Design Patterns: Elements of Reusable Object-Oriented Software (GoF, 1994), Chapter 5: Behavioral Patterns - Template Method.

  2. Cwalina, K., Abrams, B. - Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries (2nd Edition, 2008) - Discusses template method in the context of framework extensibility.

  3. Martin, R.C. - Agile Software Development: Principles, Patterns, and Practices (2002) - Template Method and the Hollywood Principle in the context of SOLID.

  4. Bloch, J. - Effective Java (3rd Edition, 2018), Item 20 - Prefer interfaces to abstract classes; discusses trade-offs relevant to Template Method.

  5. Mikhajlov, L., Sekerinski, E. - "A Study of the Fragile Base Class Problem" (ECOOP 1998) - Formal analysis of the risks inherent in inheritance-based patterns like Template Method.

  6. Freeman, E., Robson, E. - Head First Design Patterns (2nd Edition, 2020) - Chapter 8: The Template Method Pattern with the Hollywood Principle.