Template Method — Junior Level¶
Source: refactoring.guru/design-patterns/template-method Category: Behavioral — "Concerned with algorithms and the assignment of responsibilities between objects."
Table of Contents¶
- Introduction
- Prerequisites
- Glossary
- Core Concepts
- Real-World Analogies
- Mental Models
- Pros & Cons
- Use Cases
- Code Examples
- Coding Patterns
- Clean Code
- Best Practices
- Edge Cases & Pitfalls
- Common Mistakes
- Tricky Points
- Test Yourself
- Tricky Questions
- Cheat Sheet
- Summary
- What You Can Build
- Further Reading
- Related Topics
- Diagrams & Visual Aids
Introduction¶
Focus: What is it? and How to use it?
Template Method is a behavioral design pattern that defines the skeleton of an algorithm in a base class and lets subclasses override specific steps without changing the algorithm's overall structure.
Imagine a coffee-making routine: boil water, brew, pour into cup, add condiments. Tea follows the same structure but brews differently and adds different condiments. The skeleton is identical; only the variable steps change. Template Method captures the skeleton in a base class, marks the variable steps as abstract or protected, and lets subclasses fill them in.
In one sentence: "Lock the algorithm; let subclasses fill in the blanks."
Template Method is the canonical use of inheritance for code reuse. It's widespread in frameworks: Spring's JdbcTemplate, Java's InputStream, JUnit's TestCase — all use it to provide a fixed lifecycle while letting users customize specific steps.
Prerequisites¶
What you should know before reading this:
- Required: Basic OOP — classes, inheritance, abstract methods.
- Required: Polymorphism — calling overridden methods through a base reference.
- Helpful: Understanding of
final,abstract,protectedkeywords. - Helpful: A taste of why duplicating algorithm structure is a smell — Template Method removes it.
Glossary¶
| Term | Definition |
|---|---|
| Template Method | The base-class method defining the algorithm's skeleton. Often final. |
| Abstract Step | A method the subclass MUST implement. Pure abstract. |
| Hook | An optional method with a default implementation; subclasses may override. |
| Concrete Step | A method already implemented in the base class. Subclasses can't (or shouldn't) override. |
| Algorithm Skeleton | The fixed sequence of steps defined by the Template Method. |
| Inversion of control (IoC) | The base class calls into the subclass, not the other way around — Hollywood Principle ("Don't call us, we'll call you"). |
Core Concepts¶
1. Skeleton in the Base Class¶
A method in the base class defines the order of steps:
abstract class Beverage {
public final void make() {
boilWater();
brew();
pourIntoCup();
addCondiments();
}
}
make() is the Template Method. Its order is fixed.
2. Steps Are Methods (Some Overridable)¶
Each step is a method: - boilWater() — concrete (same for all beverages). - brew() — abstract (each beverage brews differently). - pourIntoCup() — concrete. - addCondiments() — abstract or hook (default: nothing).
3. Subclasses Fill in the Variable Steps¶
class Tea extends Beverage {
protected void brew() { System.out.println("steeping tea"); }
protected void addCondiments() { System.out.println("adding lemon"); }
}
class Coffee extends Beverage {
protected void brew() { System.out.println("dripping coffee"); }
protected void addCondiments() { System.out.println("adding milk"); }
}
make() works on both — same algorithm, different steps.
4. Inversion of Control¶
The base class calls into the subclass, not vice versa. The subclass doesn't drive; it provides pieces. The framework drives.
make() ──> boilWater() (base)
──> brew() (subclass)
──> pourIntoCup() (base)
──> addCondiments() (subclass)
5. Distinct from Strategy¶
Template Method uses inheritance — subclasses override hooks. Variation per subclass, not per call. Strategy uses composition — different strategy objects. Variation at runtime per call.
Strategy is more flexible (can swap algorithms per instance); Template Method is more rigid but lighter (no extra objects).
Real-World Analogies¶
| Concept | Analogy |
|---|---|
| Template Method | A recipe with fixed steps: prep, cook, plate, serve. |
| Abstract Step | "Prepare the protein" — varies by dish (chicken, fish, tofu). |
| Hook | "Optional garnish" — default: none; chefs may add herbs. |
| Concrete Step | "Wash hands" — same for every dish. |
The classical refactoring.guru analogy is a building plan: foundation → walls → roof → finishing. The plan is fixed; specific materials (concrete vs wood vs steel) are chosen by builders. Different houses, same plan.
Another good one is HTTP request handling: parse → authenticate → authorize → handle → respond. The framework provides parse / respond; you implement handle. Same lifecycle, different endpoints.
Mental Models¶
The intuition: Picture a sandwich machine. The machine handles bread placement, slicing, wrapping. You drop in fillings. The machine is the Template Method; the fillings are the abstract steps.
Why this model helps: It makes the control flow clear. The machine drives; you provide the variable parts.
Visualization:
AbstractClass.algorithm():
┌─ step1() — concrete (defined here)
├─ step2() — abstract (subclass fills)
├─ step3() — hook (optional override)
└─ step4() — concrete
ConcreteClass extends AbstractClass:
overrides step2()
optionally overrides step3()
The Template Method is the spine; subclasses provide muscles.
Pros & Cons¶
| Pros | Cons |
|---|---|
| Eliminates duplicated algorithm structure | Inheritance-based — rigid hierarchy |
| Subclasses focus on what differs | Liskov substitution easy to break |
| Open/Closed: new variants without changing the skeleton | Hard to compose multiple variations |
| Maps cleanly to framework hooks | Subclass behavior obscured (where does it fit?) |
| Hollywood Principle — framework drives | Refactoring base affects all subclasses |
When to use:¶
- Multiple variants of an algorithm differ in specific steps but share structure
- A framework defines a lifecycle with customizable steps
- You want subclasses to focus on what differs, not the boilerplate
- The algorithm has clear before / during / after phases
When NOT to use:¶
- The algorithm has only one variant (no point in the abstraction)
- Variations are picked at runtime per call — Strategy fits better
- Composition would suffice (multiple small objects vs one big inheritance hierarchy)
- The base class would have too many
protected abstractmethods
Use Cases¶
Real-world places where Template Method is commonly applied:
- Spring's
JdbcTemplate—query()template handles connection / statement / cleanup; user provides the row mapper. - Java's
InputStream/OutputStream—read()/write()defined; subclasses provide low-level byte handling. - JUnit's
TestCase—runTest()callssetUp(),runTest(),tearDown(). - Servlet's
service()method — callsdoGet,doPost, etc. - Web framework request handling — Spring's
DispatcherServlet, Express middleware order. - Game engines' update loops —
update(),render(),physics()per frame. - Build tools — Maven/Gradle lifecycle (compile, test, package).
- Algorithms with fixed phases — sorting (
merge,partition), parsers (tokenize,parse,evaluate).
Code Examples¶
Go¶
Go doesn't have classical inheritance, but you can simulate Template Method via embedding + interfaces.
package main
import "fmt"
type Beverage interface {
Brew()
AddCondiments()
}
type baseMaker struct {
beverage Beverage
}
func (b *baseMaker) Make() {
b.boilWater()
b.beverage.Brew()
b.pourIntoCup()
b.beverage.AddCondiments()
}
func (b *baseMaker) boilWater() { fmt.Println("boiling water") }
func (b *baseMaker) pourIntoCup() { fmt.Println("pouring into cup") }
// Concrete: Tea.
type Tea struct{}
func (Tea) Brew() { fmt.Println("steeping tea") }
func (Tea) AddCondiments() { fmt.Println("adding lemon") }
// Concrete: Coffee.
type Coffee struct{}
func (Coffee) Brew() { fmt.Println("dripping coffee") }
func (Coffee) AddCondiments() { fmt.Println("adding milk") }
func main() {
tea := &baseMaker{beverage: Tea{}}
tea.Make()
fmt.Println("---")
coffee := &baseMaker{beverage: Coffee{}}
coffee.Make()
}
What it does: Make() is the template; concrete beverages implement variable steps.
How to run: go run main.go
In Go, the pattern is implemented via composition + interfaces — not inheritance. Same effect.
Java¶
Classical Template Method with inheritance.
public abstract class Beverage {
public final void make() { // template: final to prevent override
boilWater();
brew();
pourIntoCup();
addCondiments();
}
private void boilWater() { System.out.println("boiling water"); }
private void pourIntoCup(){ System.out.println("pouring into cup"); }
protected abstract void brew();
protected abstract void addCondiments();
}
public final class Tea extends Beverage {
protected void brew() { System.out.println("steeping tea"); }
protected void addCondiments() { System.out.println("adding lemon"); }
}
public final class Coffee extends Beverage {
protected void brew() { System.out.println("dripping coffee"); }
protected void addCondiments() { System.out.println("adding milk"); }
}
class Demo {
public static void main(String[] args) {
new Tea().make();
System.out.println("---");
new Coffee().make();
}
}
What it does: make() is final (can't be overridden). Subclasses fill in brew and addCondiments.
How to run: javac *.java && java Demo
Python¶
from abc import ABC, abstractmethod
class Beverage(ABC):
def make(self) -> None:
self._boil_water()
self._brew()
self._pour_into_cup()
self._add_condiments()
def _boil_water(self) -> None: print("boiling water")
def _pour_into_cup(self) -> None: print("pouring into cup")
@abstractmethod
def _brew(self) -> None: ...
def _add_condiments(self) -> None:
"""Hook: default no-op; subclasses may override."""
pass
class Tea(Beverage):
def _brew(self) -> None: print("steeping tea")
def _add_condiments(self) -> None: print("adding lemon")
class Coffee(Beverage):
def _brew(self) -> None: print("dripping coffee")
def _add_condiments(self) -> None: print("adding milk")
class WaterCup(Beverage):
"""No condiments needed."""
def _brew(self) -> None: print("just water")
# _add_condiments uses default no-op hook
if __name__ == "__main__":
Tea().make()
print("---")
Coffee().make()
print("---")
WaterCup().make()
What it does: _add_condiments is a hook (default no-op). WaterCup doesn't need to override it.
How to run: python3 main.py
Coding Patterns¶
Pattern 1: Pure Template Method¶
Intent: Fixed skeleton; abstract steps required.
When: All variants must implement the variable steps. No optionality.
Pattern 2: Template with Hooks¶
Intent: Some steps are optional; subclasses override only when needed.
public final void process() {
fetch();
if (shouldTransform()) transform(); // hook
save();
}
protected boolean shouldTransform() { return true; } // default
When: Variations may opt-in to certain steps.
Pattern 3: Skeleton with Pre/Post Hooks¶
Intent: Allow before / after customization without changing the main step.
public final void process() {
beforeProcess();
doProcess();
afterProcess();
}
protected void beforeProcess() {} // hook
protected void afterProcess() {} // hook
When: Add cross-cutting concerns (logging, metrics) per subclass.
Pattern 4: Final Template, Protected Abstract Steps¶
Intent: Lock the order; force subclasses to implement only the variable parts.
public final void make() { ... } // final: can't override
protected abstract void brew(); // must implement
private void boilWater() { ... } // private: subclass can't see
Pros: Clear contract; clear intent. When: Strict frameworks where the lifecycle must be preserved.
Clean Code¶
- Mark the Template Method
finalso subclasses can't change the algorithm structure. - Mark internal steps
protectedorprivate. Public steps invite misuse. - Name hooks clearly.
beforeSave(),afterValidate()— intent obvious. - Document the lifecycle. Subclasses need to know the order.
- Keep abstract steps small and focused. One responsibility per step.
Best Practices¶
- Prefer composition (Strategy) when variations are independent.
- Use Template Method when variations share lifecycle but differ in steps.
- Document hook semantics. "Override this to ..."; "must NOT call super" or "must call super."
- Test subclasses with the actual base class, not stubs.
- Don't make all steps overridable. Lock down what shouldn't change.
Edge Cases & Pitfalls¶
- Subclass calls
super()incorrectly — breaks the template. - Subclass overrides a step that calls itself recursively through the template — infinite loop.
- Hook with side effects in default implementation. Subclass that doesn't call super loses the side effect.
- Abstract step expecting non-null return. Subclass returns null; NPE in template.
- Liskov substitution violations. Subclass overrides a step in a way the base didn't expect (throws unexpected exception, returns out-of-range value).
- Parallel Template Methods. Two algorithms in one base class invite confusion.
Common Mistakes¶
- Public Template Method without
final. Subclass overrides the algorithm; defeats the pattern. - Public abstract steps. Callers can invoke steps out of order.
- Steps with side effects subclasses don't expect. Surprises in production.
- Too many hooks. Pattern dissolves into config-by-override.
- Abstract step with default no-op named "abstract." Confusing — default should be a hook, abstract is required.
- Subclass overrides a step but breaks the contract. Liskov violation.
- Template depending on subclass calling
super. Easy to forget; brittle.
Tricky Points¶
Template Method vs Strategy¶
Both define algorithms with variable parts. Template Method uses inheritance; variation per subclass. Strategy uses composition; variation per instance / call. Strategy is more flexible; Template Method is lighter (no extra objects).
If you find yourself with if (mode == "x") { template behavior } else { ... }, Strategy fits. If you find inheritance hierarchy with shared lifecycle, Template Method.
final on the Template¶
Mark the Template Method final (Java). This prevents subclasses from accidentally overriding the algorithm. The skeleton is fixed; only steps vary.
Hook vs abstract¶
- Abstract: subclass MUST implement. No default.
- Hook: optional override. Default behavior in base class.
Use hooks for opt-in customization; abstract for required steps.
Liskov substitution¶
A subclass shouldn't break expectations of the base. If the base says "step1 must not throw," subclasses better not throw. Template Method is fragile here — subclass writers must understand the contract.
Inheritance-only¶
In languages without inheritance (Go, Rust): use composition + interfaces. The "template" is a function or method that accepts a struct/interface implementing the steps.
Test Yourself¶
- What problem does Template Method solve?
- Why mark the Template Method
final? - What's the difference between an abstract step and a hook?
- What's the Hollywood Principle?
- Give 5 real-world examples of Template Method.
- How is Template Method different from Strategy?
Tricky Questions¶
- Q: If I add a new step to the Template, do all subclasses need to update? A: Only if it's abstract. Adding a hook with a default doesn't break existing subclasses. Adding an abstract step does — old subclasses now don't compile.
- Q: Can the Template Method itself be overridden? A: Technically yes (without
final). But that defeats the pattern — the whole point is the fixed skeleton. - Q: Why is Template Method coupled to inheritance? A: It uses overriding to vary steps. In languages without inheritance, simulate via composition (interface + delegation).
- Q: When does Template Method become a god class? A: When the base class has 20 abstract methods. Subclasses are forced to implement everything; reuse breaks down. Refactor: split into smaller templates or use Strategy.
Cheat Sheet¶
| Concept | One-liner |
|---|---|
| Intent | Define algorithm skeleton; subclasses fill steps |
| Roles | AbstractClass (skeleton), Concrete subclass (steps) |
| Hot loop | template_method() → step1() → step2() → ... |
| Sibling | Strategy (composition), Factory Method |
| Modern form | Higher-order function with callbacks |
| Smell to fix | Two classes with same structure, different details |
Summary¶
Template Method captures an algorithm's structure in a base class and lets subclasses fill in the variable parts. The base class drives (Hollywood Principle); subclasses provide pieces. Eliminates duplication of algorithm structure across variants.
Three things to remember: 1. Skeleton in the base class. Variable steps in subclasses. 2. Mark Template Method final. Lock the order. 3. Inheritance-based. For composition, use Strategy.
If you find yourself copy-pasting the same lifecycle with minor variations, Template Method is asking to be born.
What You Can Build¶
- A web request handler with parse → auth → handle → respond
- A document parser with tokenize → parse → validate → emit
- A test runner with setUp → test → tearDown
- A game loop with update → render → physics
- An ETL job with extract → transform → load
- A build tool with compile → test → package
Further Reading¶
- Design Patterns: Elements of Reusable Object-Oriented Software (GoF) — original chapter
- Effective Java, Item 19 — design and document for inheritance
- refactoring.guru — Template Method
- Patterns of Enterprise Application Architecture (Fowler) — Layer Supertype, Service Layer
Related Topics¶
- Strategy — composition-based variation
- Factory Method — Template often calls Factory Method
- Hollywood Principle
- Liskov substitution
- Frameworks vs libraries