SSourav Saha
HomeExperienceSoftware DesignSystem DesignLearningBooksToolsContact
SSourav Saha

Building scalable backend systems, distributed infrastructure, and cloud-native applications.

Navigation

  • Home
  • Experience
  • Software Design
  • System Design
  • Learning

More

  • Books
  • Tools
  • Contact

Connect

  • LinkedIn
  • Email

© 2026 Sourav Saha. All rights reserved.

Built with using Next.js

Software DesignTemplate Method Pattern
Software DesignBehavioral Patterns

Template Method Pattern

Define the skeleton of an algorithm in a superclass but let subclasses override specific steps without changing the overall structure.

October 20, 20245 min read
design-patternsjavatemplate-methodbehavioral

One-line Definition

Defines the invariant skeleton of an algorithm in a base class, delegating the implementation of specific variant steps to subclasses.


Problem

Suppose you're building a data mining application that parses PDF, CSV, and Word documents. The process for all three is structurally identical: open the file, extract the raw data, parse the data, analyze it, and generate a report. If you write three separate classes, you'll copy-paste the orchestration code (opening, analyzing, reporting) three times. The Template Method Pattern solves this by moving the overall workflow into a single base class method, forcing subclasses to implement only the parsing logic specific to their file type.


Real-world Analogy

Think of baking a cake. The core steps are always the same: preheat the oven, mix the ingredients, pour into a pan, bake for 30 minutes, and let it cool. The template method dictates this strict sequence. However, what ingredients you mix determines whether it's a Chocolate Cake or a Vanilla Cake. The subclasses provide the specific ingredients, but they cannot change the baking sequence.


Structure

  • AbstractClass
    • Contains the templateMethod() which defines the skeleton of the algorithm. This method is usually marked final so subclasses cannot override the workflow.
    • Declares abstract methods representing steps that subclasses must implement.
    • Optionally provides "hook" methods with empty or default implementations that subclasses may override.
  • ConcreteClass
    • Implements the abstract step methods to provide specific behaviors.
  • Client
    • Calls the templateMethod() on a concrete instance, unaware of the specific steps.

Diagram

classDiagram
    class Client {
    }
    class AbstractClass {
        <<abstract>>
        +templateMethod() final
        #stepOne() abstract
        #stepTwo() abstract
        #hookMethod()
    }
    class ConcreteClassA {
        #stepOne()
        #stepTwo()
    }
    class ConcreteClassB {
        #stepOne()
        #stepTwo()
        #hookMethod()
    }
    
    Client --> AbstractClass
    ConcreteClassA --|> AbstractClass
    ConcreteClassB --|> AbstractClass

Code Walkthrough

Notice how buildHouse() (the template method) is marked final in HouseBuilder. The client just calls buildHouse(), and the base class orchestrates the execution of both the shared methods and the subclass-specific abstract methods.

abstract class HouseBuilder {
    // The Template Method: Defines the skeleton and is final
    public final void buildHouse() {
        buildFoundation();
        buildWalls();
        buildRoof();
        if (wantsPool()) { // Hook method
            buildPool();
        }
        System.out.println("House is complete!");
    }

    // Common implementation across all subclasses
    private void buildFoundation() {
        System.out.println("Laying standard cement foundation");
    }

    // Steps to be implemented by subclasses
    protected abstract void buildWalls();
    protected abstract void buildRoof();

    // Hook: Subclasses can optionally override this
    protected boolean wantsPool() {
        return false;
    }

    private void buildPool() {
        System.out.println("Digging and building a swimming pool");
    }
}

class WoodenHouse extends HouseBuilder {
    @Override
    protected void buildWalls() {
        System.out.println("Building wooden walls");
    }

    @Override
    protected void buildRoof() {
        System.out.println("Building wooden shingle roof");
    }
}

class LuxuryStoneHouse extends HouseBuilder {
    @Override
    protected void buildWalls() {
        System.out.println("Building solid stone walls");
    }

    @Override
    protected void buildRoof() {
        System.out.println("Building reinforced tile roof");
    }

    // Overriding the hook
    @Override
    protected boolean wantsPool() {
        return true; 
    }
}

class Main {
    public static void main(String[] args) {
        System.out.println("--- Building Wooden House ---");
        HouseBuilder woodHouse = new WoodenHouse();
        woodHouse.buildHouse();

        System.out.println("\n--- Building Luxury Stone House ---");
        HouseBuilder luxuryHouse = new LuxuryStoneHouse();
        luxuryHouse.buildHouse();
    }
}

Bad vs Good

Bad Approach

Problems

  • Massive code duplication. The orchestration logic (open(), close(), log()) is repeated in every class.
  • If the core workflow changes (e.g., adding a validate() step), you must update every single class manually.
class CSVParser {
    public void parseFile() {
        System.out.println("Opening file");
        System.out.println("Extracting CSV data"); // Specific logic
        System.out.println("Closing file");
    }
}

class XMLParser {
    public void parseFile() {
        System.out.println("Opening file");
        System.out.println("Extracting XML data"); // Specific logic
        System.out.println("Closing file");
    }
}

Better Approach

Improvements

  • The core workflow is strictly enforced by the base class.
  • Subclasses are extremely lean; they only implement what makes them unique.
  • Hooks allow optional customization without breaking the core algorithm.
abstract class DataParser {
    public final void parseFile() {
        System.out.println("Opening file");
        extractData(); // Abstract step
        System.out.println("Closing file");
    }
    protected abstract void extractData();
}

Pros vs Cons

ProsCons
Eliminates code duplication by pulling workflow logic into a superclassTightly couples subclasses to the base class via inheritance
Forces subclasses to respect a specific algorithmic sequenceBase class can become bloated if the algorithm has too many steps
Hooks provide flexible extension points for optional behaviorsViolates the Liskov Substitution Principle if subclasses suppress base behavior
Follows the Hollywood Principle: "Don't call us, we'll call you"Less flexible than the Strategy pattern at runtime

When to Use

  • You have several classes that execute an almost identical sequence of steps, differing only in specific details.
  • You want to strictly control an algorithmic workflow while letting clients extend only certain parts of it via hooks.
  • You want to completely eliminate code duplication in closely related classes.

When Not to Use

  • The algorithm's structure changes dynamically at runtime (use the Strategy pattern instead).
  • You want to favor Composition over Inheritance (Template Method relies entirely on classical Inheritance).

Real-world Examples

  • java.util.AbstractList (Provides a skeleton for List implementations).
  • java.io.InputStream and java.io.OutputStream (Base methods call abstract read() / write() methods).
  • Spring's JdbcTemplate, RestTemplate, etc. (Though Spring often mixes this with Callbacks/Strategy).
  • JUnit's setUp() / tearDown() hooks around test execution.

Key Takeaway

The Template Method Pattern uses inheritance to define a rigid algorithmic workflow in a base class, forcing subclasses to fill in the blanks. It strongly adheres to the "Hollywood Principle" (Don't call us, we'll call you) by having the base class dictate the flow and invoke subclass methods. Use it when the sequence of operations is fixed, but avoid it if you need the runtime flexibility of the Strategy pattern.

PreviousDecorator PatternNextComposite Pattern