1. The Problem
Problem: Shared Workflow, Variable Steps
Many systems follow a fixed overall process, but certain steps inside that process can vary. Examples:
- Payment processing pipelines
- Data parsing/validation pipelines
- Framework lifecycle hooks (e.g., Django, Spring)
- Game engines where “algorithm skeleton” stays the same but behaviors differ
Developers often solve this with:
def process():
step1()
if mode == "A":
step2A()
elif mode == "B":
step2B()
step3()
This leads to:
- Conditionals scattered across the workflow
- Hard-to-extend logic
- Violation of Open/Closed Principle
- Tight coupling between workflow and step variations
We need a solution where:
- The overall workflow is fixed
- Variable steps are customizable
- New variations don’t change core logic
2. Template Method Pattern: Fix the Algorithm Structure, Vary the Steps
Template Method solves this by defining a fixed algorithm skeleton in a base class and letting subclasses customize specific parts.
Core idea:
- Define the workflow skeleton once
- Mark certain steps as customizable hooks
- Subclasses override only the varying parts
- The algorithm order and structure remain guaranteed
Two roles exist:
- Abstract Class (Template) Holds the fixed algorithm and defines extension points
- Concrete Subclasses Provide custom implementations for variable steps
Benefits:
- Enforces consistent workflow
- Eliminates branching logic
- Encourages extension instead of modification
- Centralizes algorithm structure in one place
Use Template Method when:
- There is a stable algorithm structure
- Some steps should be customizable
- You want to enforce execution order
- You want reuse + controlled variation
3. Implementation: Template Method in Python
Abstract Template
from abc import ABC, abstractmethod
class DataProcessor(ABC):
def process(self, data):
self.read(data)
cleaned = self.clean(data)
transformed = self.transform(cleaned)
self.save(transformed)
def read(self, data):
print(f"Reading data: {data}")
@abstractmethod
def clean(self, data):
pass
@abstractmethod
def transform(self, data):
pass
def save(self, data):
print(f"Saving processed data: {data}")
Key points:
process()is the template method- It defines workflow order:
read → clean → transform → save clean()andtransform()are customizable hooks
Concrete Implementations
class CSVProcessor(DataProcessor):
def clean(self, data):
return data.strip()
def transform(self, data):
return data.upper()
class JSONProcessor(DataProcessor):
def clean(self, data):
return data.replace(" ", "")
def transform(self, data):
return f"JSON({data})"
Usage
processor = CSVProcessor()
processor.process(" sample csv data ")
processor = JSONProcessor()
processor.process(" sample json data ")
No conditionals. No branching. Workflow is guaranteed. Behavior is extensible.
4. When to Use Template Method (and When Not To)
Strong Signals You Need Template Method
- “The flow is always the same, but steps differ.”
- “We need enforceable process order.”
- “Teams extend behavior but must not break workflow.”
- “Common logic must live in one place.”
- “Subclass specialization fits the domain model.”
Not a Good Fit When
- Steps are independent and fully interchangeable → Strategy is better
- You want runtime swapping of behavior → Strategy again
- Variation does not justify inheritance → simple functions suffice
- You want composition instead of inheritance → favor delegation patterns
5. Common Pitfalls
- Overusing inheritance instead of composition → unnecessary hierarchy
- Too many hooks → unreadable abstractions
- Making algorithm too rigid → loss of flexibility
- Violating the guarantee by leaking control to subclasses
- Forgetting that subclasses shouldn’t change execution order
Good rule: Template Method = fixed algorithm + controlled customization
6. Strategy vs Template Method (Mental Model)
Both solve “variation in behavior,” but in different ways:
| Strategy Pattern | Template Method Pattern |
|---|---|
| Behavior chosen at runtime | Behavior chosen by subclass |
| Uses composition | Uses inheritance |
| No fixed workflow enforced | Fixed workflow enforced |
| Caller decides behavior | Base class decides process |
If the question is: “I want interchangeable behaviors.” → Strategy
If the question is: “I want guaranteed workflow with customizable steps.” → Template Method