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 markedfinalso 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.
- Contains the
- ConcreteClass
- Implements the abstract step methods to provide specific behaviors.
- Client
- Calls the
templateMethod()on a concrete instance, unaware of the specific steps.
- Calls the
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
| Pros | Cons |
|---|---|
| Eliminates code duplication by pulling workflow logic into a superclass | Tightly couples subclasses to the base class via inheritance |
| Forces subclasses to respect a specific algorithmic sequence | Base class can become bloated if the algorithm has too many steps |
| Hooks provide flexible extension points for optional behaviors | Violates 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 forListimplementations).java.io.InputStreamandjava.io.OutputStream(Base methods call abstractread()/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.