What is the Template Method design pattern, and what problem does it solve?
answer
- skeleton in base, steps in subtype
- primitive = must override, hook = may override
- template method is final
- Hollywood Principle: don't call us
- inheritance twin of Strategy
basics
~20 sA base type defines one method holding the fixed steps of an algorithm, in a fixed order. Some of those steps are left unimplemented, and subtypes fill them in. The overall shape stays the same for every subtype.
solid answer
~50 sTemplate Method is a behavioral pattern that puts the invariant skeleton of an algorithm into a single method on a base type — the template method — which calls a fixed sequence of steps. Varying steps are declared either as abstract primitive operations (subtypes must supply them) or as hooks with a default body (subtypes may override). The template method itself is normally made non-overridable so the order and invariants cannot be changed. The payoff is reuse without duplication: shared control flow lives in one place, and only the differences are written per subtype. It is inversion of control — the base class calls down into the subtype ("don't call us, we'll call you") rather than the subtype orchestrating. Classic uses: framework request lifecycles, test setUp/run/tearDown, build and report pipelines. Strategy solves the same variability problem with composition instead of inheritance.
code
pseudocode · 23 linesabstract class ReportExporter {
// the template method: fixed skeleton, cannot be overridden
final export(rows, sink) {
open(sink)
try {
if (wantsHeader()) write(sink, header()) // hook + primitive
for (row in rows) write(sink, format(row)) // primitive
write(sink, footer()) // hook w/ default
} finally {
close(sink) // invariant cleanup
}
}
abstract header(): String // primitive: subtype MUST supply
abstract format(row): String // primitive: subtype MUST supply
wantsHeader(): Boolean = true // hook: subtype MAY override
footer(): String = "" // hook: subtype MAY override
}
class CsvExporter extends ReportExporter {
header() = "id,name"
format(row) = row.id + "," + row.name
}go deeper
Name it as a behavioural pattern: base class holds the algorithm's fixed steps, subclasses fill in the blanks. Give one concrete example (test setUp/tearDown, export pipeline).
Add the vocabulary — template method, primitive operation, hook — explain why the template method is final, and contrast with Strategy (inheritance vs composition).
Discuss inversion of control / Hollywood Principle, visibility of the extension points, testing subclasses in isolation, and when the hierarchy becomes a liability (fragile base class, single-inheritance limits).
Treat the protected step set as a published contract with versioning and deprecation consequences; discuss when to expose a lifecycle at all versus composition/plugin interfaces, and the migration path from a hierarchy to injected collaborators.
## The problem Suppose you have several procedures that are *almost* the same. A CSV export and a JSON export both: open a destination, write a header, loop over rows writing each one, write a footer, close the destination. Only *how a row is formatted* and *what the header looks like* differ. If you copy-paste the whole procedure twice, you duplicate the control flow: the loop, the ordering, the resource cleanup, the error handling. Every later fix (say, "always close the destination even on failure") must be made in every copy, and one copy will eventually be forgotten. Template Method removes that duplication by separating **what stays the same** (the *skeleton*, or *invariant* part) from **what varies** (the *variant* steps). ## The mechanism Define a base type (abstract class, or any type that can hold both concrete and unimplemented members) with: - **The template method** — one concrete method containing the algorithm as a series of calls to named steps, in the correct order, with the shared control flow (loops, conditionals, try/finally cleanup) around them. This method is the *skeleton*. - **Primitive operations** — abstract/unimplemented steps the template method calls. Each subtype **must** provide them. These are the mandatory variation points. - **Hook operations** ("hooks") — steps that already have a default implementation, often empty (a *no-op*) or returning a sensible default. Subtypes **may** override them to inject extra behaviour or to influence the flow (e.g. a `shouldWriteHeader()` hook returning `true` by default). - **Concrete shared operations** — helper methods the template method calls that are not meant to vary at all. Subtypes then contain *only* the differences. They never re-state the ordering. Using GoF vocabulary, the participants are `AbstractClass` (holds the template method + declares primitive operations) and `ConcreteClass` (implements the primitive operations). ## Inversion of control In ordinary code *your* code calls *library* code. With Template Method the direction flips at the extension point: the framework's template method calls **down** into your override. This is the **Hollywood Principle** — "Don't call us, we'll call you." You do not decide *when* your step runs; the skeleton does. That is exactly why frameworks (as opposed to libraries) lean on this pattern: they own the lifecycle and hand you slots inside it. Familiar real-world instances: - Unit-test frameworks: the runner calls `setUp()` → your test body → `tearDown()`, always in that order, with cleanup guaranteed. - Web-request base classes: a `service()`/`handle()` method that parses the request, dispatches to `doGet`/`doPost`, and always writes/flushes the response. - Build or ETL pipelines: `validate → extract → transform → load → report`, where only `transform` varies per data source. - Sorting/serialization frameworks that own the traversal and call your comparison or field-writing step. ## Protecting the skeleton The pattern's value comes from the skeleton being *un-bypassable*, so: - Mark the template method non-overridable (`final` in Java/C#, non-`open` in Kotlin, non-`virtual` in C++) so a subtype cannot silently replace the order. - Give the steps the narrowest visibility that works (protected / package-visible): they are extension points for subtypes, not public API for callers. - Keep the number of steps small; each one is a promise you must keep supporting. ## Trade-offs at a glance **Pros:** removes duplicated control flow; the algorithm reads as a single, self-documenting outline; invariants (ordering, cleanup, validation) are enforced centrally; new variants are cheap. **Cons:** it is *inheritance*, so variation is fixed at compile time — you cannot swap a step at runtime, and a subtype can usually vary along only one axis (single inheritance). Subtypes are tightly coupled to the base class's internals, which invites the *fragile base class* problem: changing the skeleton can break subtypes you cannot see. Overuse produces deep, hard-to-follow hierarchies where reading one method means reading three files. ## Relationship to neighbouring patterns - **Strategy** solves the same "one step varies" problem by *composing* an object that implements the step; swappable at runtime, no inheritance. - **Factory Method** is frequently a *specialisation* of Template Method: the skeleton needs an object, and creating it is the deferred step. - **Decorator** adds behaviour around a whole object from the outside; Template Method inserts behaviour *inside* a fixed algorithm. In languages with first-class functions, a template method is often written as a higher-order function that takes the varying steps as lambdas — same intent, no class hierarchy.
- Why is the template method itself usually marked final / non-overridable?Because the whole point is that the ordering and the invariants (validation, cleanup, logging) are guaranteed. If a subtype can override the skeleton, it can drop a step or reorder it, and the guarantee the base class advertises evaporates — you are back to duplicated, divergent control flow.
- Where have you seen Template Method in a framework you use?Test frameworks calling setUp/tearDown around each test, HTTP base handlers whose service() dispatches to doGet/doPost and always flushes the response, and pipeline base classes that run validate→process→report. In all of them the framework owns the order and calls your override.
A recipe card that says: preheat, mix the batter, bake 30 minutes, cool, then frost. "Frost" is left blank — chocolate, vanilla, none. Everyone bakes the same way; only the blank changes. The card is laminated so nobody reorders the steps.
saying these in an interview costs you the question
- Saying it's a creational pattern — it is behavioural; it varies steps of an algorithm, not object creation.
- Claiming subclasses can change the order of steps — that's precisely what the pattern forbids.
- Confusing it with Strategy: Template Method uses inheritance and compile-time binding, Strategy uses composition and runtime swapping.
- Putting the varying steps as public methods on the base class — they are extension points for subtypes, not caller API.
- Claiming every step must be abstract; hooks with defaults are a core part of the pattern.