How do the Strategy and Template Method design patterns differ, and what determines which one you should reach for?
answer
- Template Method = inheritance, compile time, base calls down
- Strategy = composition, runtime, context delegates out
- Hollywood Principle: don't call us, we'll call you
- Two varying dimensions → subclass explosion → Strategy
- Hybrid: concrete skeleton + injected steps
basics
~20 sBoth let part of an algorithm vary. Template Method uses inheritance: a base class fixes the steps and subclasses override some of them. Strategy uses composition: the varying algorithm is a separate object you plug in, swappable at runtime.
solid answer
~60 sTemplate Method puts the invariant algorithm skeleton in a base class method that calls abstract or overridable hook steps; subclasses supply the varying steps. The binding is by inheritance, chosen at compile time, one variation per subclass, and the subclass cannot change the order of steps — that is exactly the point, it enforces the sequence. Strategy extracts the whole varying algorithm into its own interface; the context holds a reference to one implementation and delegates to it. The binding is by composition, so it can be swapped at runtime, injected for tests, and a single strategy can be reused by several contexts. Prefer Template Method when you genuinely want to lock a sequence and the variation is a few small steps inside it — a report generator, a test lifecycle, a transactional workflow. Prefer Strategy when the whole algorithm varies, when you need runtime selection or multiple varying dimensions, or when inheritance would blow up combinatorially. Strategy is usually the safer default because it avoids the fragile base class problem.
code
pseudocode · 15 lines// Template Method: sequence fixed in the base, steps overridden
abstract class Importer {
final import(src) { // cannot be overridden
open(src); val rows = parse(src); validate(rows); save(rows); close()
}
abstract parse(src) // hook
abstract validate(rows) // hook
}
// Strategy: whole algorithm injected, swappable at runtime
interface Parser { parse(src): Rows }
class Importer(private parser: Parser) {
import(src) { open(src); save(parser.parse(src)); close() }
}
// importer = Importer(if (file.isCsv) CsvParser() else JsonParser())go deeper
Say Template Method varies steps via subclassing and Strategy plugs in a whole algorithm object; give one example of each.
Add the binding-time distinction (compile time vs runtime), the single-inheritance limit, and the subclass-explosion argument.
Discuss fragile base class, testability, the hybrid skeleton-with-injected-steps refactor, and when the enforced sequence is worth the inheritance cost.
Frame it as composition-over-inheritance policy across a codebase: what the extension points cost readers, how framework SPIs choose one or the other, and how to migrate an inherited hierarchy incrementally without breaking downstream implementors.
## Definitions first - **Algorithm skeleton** — the fixed sequence of steps that must always happen in the same order. - **Hook / hook method** — a step in that skeleton deliberately left open for a subclass to fill in or override. - **Composition** — object A holds a reference to object B and delegates work to it. - **Inheritance** — class A extends class B and inherits/overrides its behaviour; the relationship is fixed when the class is compiled. ## Template Method A base class defines a method — the template method — that spells out the algorithm as a series of calls to smaller methods. Some of those smaller methods are abstract (must be implemented) or virtual with a default (may be overridden). The template method itself is usually sealed/final so subclasses cannot reorder or skip steps. ``` abstract class ReportJob { final run() { // the template method open() var rows = fetch() // abstract hook var doc = format(rows) // abstract hook deliver(doc) // hook with a default close() } } ``` This is *inversion of control at the class level*: the base class calls down into the subclass ("don't call us, we'll call you" — the Hollywood Principle). Real-world examples: `java.io.InputStream#read`, JUnit's setUp/test/tearDown lifecycle, Spring's `AbstractController`, servlet `HttpServlet#service` dispatching to `doGet`/`doPost`. **Strengths.** The sequence is enforced by construction — a subclass literally cannot forget to close the resource. Shared code lives once in the base. Very little ceremony for small variations. **Weaknesses.** - **Single inheritance limit** — in most languages a class can extend only one base, so a type that needs two template hierarchies is stuck. - **Combinatorial explosion** — two independent varying steps with 3 options each need 9 subclasses. - **Fragile base class** — changing the base's protected surface silently breaks subclasses you cannot see; the base and the subclass share mutable state and lifecycle. - **Compile-time binding** — you cannot swap the variation for a given instance at runtime. - **Testing** — you often must instantiate the whole hierarchy to test one step. ## Strategy The entire varying algorithm becomes a first-class object behind an interface. A *context* holds one and delegates. ``` interface PricingStrategy { price(cart): Money } class Checkout(private strategy: PricingStrategy) { total(cart) = strategy.price(cart) } ``` **Strengths.** - **Runtime swap** — pick by config, feature flag, tenant, A/B bucket, or user input. - **Independent variation** — multiple strategy slots compose multiplicatively without subclass explosion (a `Checkout` can take a pricing strategy *and* a tax strategy). - **Testable and reusable** — a strategy is a plain object testable in isolation and shareable across contexts. - **Favours composition over inheritance**, avoiding the fragile base class problem entirely. **Weaknesses.** - More types and wiring; the client (or a factory/DI container) must know which strategy to supply. - Strategies see only what the context passes them, so a strategy needing lots of context state leads to fat parameter objects or leaking the context itself. - With many trivial strategies the indirection can obscure a simple `switch`. ## Choosing Ask three questions: 1. **How much varies?** A few steps inside a fixed sequence → Template Method. The whole computation → Strategy. 2. **Must the sequence be enforced?** If skipping a step is a correctness or safety bug, Template Method encodes that guarantee in the type system. 3. **When is the variation known?** Compile time and one dimension → Template Method is acceptable. Runtime, or several independent dimensions → Strategy. A common refactoring path is Template Method → Strategy: keep the skeleton as a concrete (non-abstract) class, but inject each hook as a collaborator. You get the enforced sequence *and* runtime composition. This hybrid is what most modern frameworks actually do (a pipeline object composed of injected steps). ## Edge cases - In languages with first-class functions, a Strategy is often just a function parameter or lambda; the pattern is unchanged, only the interface declaration disappears. - Strategy and **State** are structurally identical. The distinction is who chooses: with Strategy the client picks and it usually stays fixed for the operation; with State the object transitions between its own states as events arrive. - Strategy and **Bridge** also look alike. Bridge separates a whole abstraction hierarchy from an implementation hierarchy so both can evolve; Strategy varies one algorithm. - Over-applying Template Method produces deep hierarchies where reading one flow means jumping through four files — a real maintainability cost that a senior answer should name.
- Your Template Method hierarchy needs two steps that vary independently, 3 options each. What happens, and what do you do?You get a 3x3 combinatorial explosion — 9 subclasses, or a fragile mix-in scheme. Convert each varying step into an injected Strategy so the skeleton class stays concrete and the two dimensions compose: 3 + 3 implementations instead of 9.
- Strategy and State have the same class diagram. What actually distinguishes them?Who chooses the delegate and how often. In Strategy the client selects the algorithm and it typically stays fixed for the call; in State the object (or the current state object) transitions to another state as events arrive, so the delegate changes over the object's lifetime and encodes a state machine.
Template Method is a recipe card with two blanks you fill in — the steps and their order are printed and you cannot rearrange them. Strategy is hiring a different chef for the dish: you keep the kitchen, and the whole cooking method changes with the person you plug in.
saying these in an interview costs you the question
- Saying Strategy requires inheritance — it is defined by composition and delegation.
- Claiming Template Method lets subclasses reorder the steps; the template method fixes the order, that is its purpose.
- Treating them as interchangeable with no mention of compile-time vs runtime binding.
- Asserting Strategy is always better — it costs types and wiring, and loses the enforced sequence.
- Confusing Template Method with the Factory Method pattern because both use subclass hooks.