Template Method Pattern
Template Method works because a non-overridable method in a base class fixes the order of an algorithm's steps and calls each step through a virtual method, so subclasses can replace what a step does but never the sequence or the wiring between steps. The control flow lives once, in the parent; the variation lives in the children. This is the literal Hollywood Principle — "Don't call us, we'll call you": the subclass never drives the algorithm, the parent's template method calls down into the subclass's overrides at the moments it chooses.
The mechanism, concretely
You have three report formats — CSV, HTML, PDF — and all three follow the same arc: collect → process → format → print. Only the three middle behaviours differ per format; the order and the printing never do. Put the arc in one final method on an abstract ReportGenerator, declare the varying steps abstract, and let each subclass fill them in. The base class owns the skeleton; the subclass owns the muscle.
Worked trace with real values
Run new CSVReportGenerator().generateReport() over a tiny two-line raw feed. The base method drives; the subclass supplies the per-step behaviour. Follow the value as it threads through.
| Step | Defined in | Input | Output |
|---|---|---|---|
collectData() | CSV subclass | — | "id,amt\n7,42\n9,13" |
processData(raw) | CSV subclass | that raw string | 2 parsed rows; running total = 42 + 13 = 55 |
formatReport(rows) | CSV subclass | 2 rows + total | "id,amt\n7,42\n9,13\nTOTAL,55" |
printReport(report) | base class | that CSV string | writes 4 lines to stdout |
Swap in HTMLReportGenerator and only the three middle outputs change — collectData() might hit a REST endpoint, formatReport() emits <table>…<tr>…55</tr></table> — but step 4 and the 1→2→3→4 order are byte-for-byte identical because they live in the parent.
The two guardrails the catalog version forgets
A catalog drawing of Template Method shows the skeleton and the abstract steps and stops. Two practical mechanisms make it actually safe to ship:
1. Lock the skeleton with final
The whole value proposition — "the order is fixed" — is only enforced if a subclass cannot override the template method. Declare it final (Java/C++) or document it as sealed. Without this, a subclass can override generateReport(), reorder the steps, or skip printReport(), and you have silently lost the invariant the pattern existed to protect.
2. Use hook methods for optional steps
Not every step is required by every subclass. A hook is a step the base class implements with a sensible default (often empty, or a boolean that returns true) so overriding is optional. The template method calls the hook; subclasses that care override it, the rest inherit the no-op. This is how you add optional behaviour without forcing every subclass to write empty methods.
Here is the report generator made correct — template method final, one abstract step set, and a boolean hook that lets a subclass opt into a footer:
public abstract class ReportGenerator {
// Skeleton — FINAL so no subclass can reorder or skip steps.
public final void generateReport() {
String raw = collectData();
Rows processed = processData(raw);
String report = formatReport(processed);
if (includeFooter()) { // hook call site
report += formatFooter(processed);
}
printReport(report); // shared, not overridable
}
// Required steps — subclasses MUST supply these.
protected abstract String collectData();
protected abstract Rows processData(String raw);
protected abstract String formatReport(Rows processed);
// HOOK: default behaviour, override is OPTIONAL.
protected boolean includeFooter() { return false; }
protected String formatFooter(Rows r) { return ""; }
// Shared step — defined once, reused by all.
private void printReport(String report) {
System.out.println(report);
}
}
class CSVReportGenerator extends ReportGenerator {
@Override protected String collectData() { return "id,amt\n7,42\n9,13"; }
@Override protected Rows processData(String raw) { return Rows.parseCsv(raw); }
@Override protected String formatReport(Rows r) { return r.toCsv(); }
@Override protected boolean includeFooter() { return true; } // opts in
@Override protected String formatFooter(Rows r) { return "\nTOTAL," + r.sum(); }
}
class HTMLReportGenerator extends ReportGenerator {
@Override protected String collectData() { return Api.fetch("/sales"); }
@Override protected Rows processData(String raw) { return Rows.parseJson(raw); }
@Override protected String formatReport(Rows r) { return r.toHtmlTable(); }
// inherits includeFooter() == false: no footer, zero boilerplate.
}Why the naive version is wrong
The original page left generateReport() as a plain public method and had no hook. That compiles, but it leaks the invariant: a junior dev writing PDFReportGenerator can legally write @Override public void generateReport() and call formatReport() before processData() — the compiler is happy, the bug is silent, and the "skeleton" the pattern promised no longer exists. Marking it final turns that mistake into a compile error. And without a hook, an optional footer forces every subclass to implement an empty formatFooter() — the boilerplate the pattern was supposed to remove.
The stakes are highest when the order is the safety property. A payment flow whose skeleton is validate → authorize → capture must never let a subclass capture money before it authorizes; a compliance pipeline must never let a subclass emit before it redacts. A non-final template method lets exactly that happen silently — which is why "seal the skeleton" is a correctness requirement in those domains, not a style preference.
Pitfalls
- Forgetting
final/ the fragile base class. If the template method isn't sealed, subclasses override it and the invariant is gone. Conversely, calling overridable steps from a base-class constructor is a classic trap: in Java the subclass field isn't initialized yet when the parent constructor runs, so the overridden step seesnull. - Inheritance explosion. Template Method is one-axis variation via subclassing. If you need to vary two things independently (say data source × output format), naive subclassing gives you N×M classes. That's a signal to switch to composition (Strategy).
- Protected-step soup. Decomposing into too many fine-grained abstract steps forces every subclass to implement a long list, much of it trivial. Keep the step count small; promote truly-optional ones to hooks with defaults.
- Hidden control flow. A reader of
CSVReportGeneratorsees nomainloop — the order lives in the parent they may not have open. Mitigate with a doc comment on the template method listing the call order. - Liskov violations in steps. A subclass step that throws, returns
null, or has side effects the skeleton doesn't expect breaks the contract the template method assumes. Document each step's pre/post-conditions.
When to use it — and when to reach for Strategy instead
Template Method and Strategy solve the same problem — vary part of an algorithm — but with opposite mechanics. Template Method varies steps by inheritance (compile-time, the variation is baked into a subclass). Strategy varies a whole algorithm by composition (run-time, you inject a behaviour object). The deciding question is when the variation is chosen and how many axes vary.
| Template Method | Strategy | |
|---|---|---|
| Mechanism | Subclass overrides steps | Inject a behaviour object |
| Binding time | Compile-time (per subclass) | Run-time (swap the object) |
| Controls the flow | The base class (Hollywood) | The client / context calls the strategy |
| Varies | Individual steps, one axis | The whole pluggable algorithm |
| Cost | Inheritance coupling; class per variant; can't switch at runtime | Extra object + interface; flow no longer centralized |
Decision signals
- Choose Template Method when the overall sequence is fixed and must be protected, only a few steps differ, the set of variants is known at compile time, and you want the order enforced in one place. (Frameworks: JUnit's
setUp → test → tearDown, Spring'sAbstractController, servletservice()→doGet/doPost.) - Choose Strategy when you must switch behaviour at runtime, the same variation is needed across unrelated classes, or you have two or more independent axes of variation (composition avoids the N×M subclass blow-up).
Concrete call: for the three report formats picked once at startup and sharing a strict collect→process→format→print arc, Template Method is the right tool — the order is the invariant worth protecting, and you'll never need to swap formats mid-run. The moment a requirement appears like "any data source paired with any output format, chosen by a config flag at runtime," stop subclassing and inject a DataSource strategy and a Formatter strategy instead.
One-liner: choose Template Method when the skeleton is sacred and variants are few and compile-time; prefer Strategy when behaviour must be swapped at runtime or varies on more than one axis.
Takeaways
- The template method holds the order; subclasses hold the steps. Inversion of control ("don't call us, we'll call you") is the whole point.
- Mark the template method
finalso the skeleton can't be reordered or skipped — that's the guardrail that makes the invariant real, not aspirational. - Use hook methods (default-implemented steps) for optional behaviour so subclasses override only what they care about and inherit sensible defaults for the rest.
- Template Method is inheritance, one axis, compile-time. When variation needs to be runtime or multi-axis, switch to Strategy's composition before subclasses multiply.
Re-authored and deepened for this guide. Sources: Gamma, Helm, Johnson & Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software (1994), the original Template Method and Hollywood Principle discussion; Refactoring.Guru, "Template Method"; Freeman & Robson, Head First Design Patterns, 2nd ed. (hook methods and the Strategy contrast); Joshua Bloch, Effective Java, 3rd ed., Item 19 (designing for inheritance, the constructor-calling-overridable-method trap) and Item 18 (favor composition over inheritance). Java framework examples cross-checked against the JUnit, Jakarta Servlet, and Spring AbstractController APIs.
🤖 Don't fully get this? Learn it with Claude
Stuck on Template Method Pattern? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Template Method Pattern** (OO & Low-Level Design) and want to truly understand it. Explain Template Method Pattern from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Template Method Pattern** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Template Method Pattern** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Template Method Pattern** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.