skip to content

How does Template Method differ from the Strategy pattern, and when would you choose composition over an abstract-class hierarchy?

level: seniorimportance: should knowfreq 50%

answer

  1. Template Method = inheritance, compile-time, one subclass
  2. Strategy = composition, run-time, swappable object/lambda
  3. Favor composition over inheritance (fragile base class)
  4. Template Method shares this/state; Strategy must be passed it
  5. Java 8 lambdas blur the two

basics

~20 s

Template Method varies steps using inheritance: a subclass overrides abstract methods, fixed at compile time. Strategy varies behavior using composition: you pass in an object (or lambda) that can change at run time. Prefer Strategy when you need flexibility or want to avoid deep class hierarchies.

solid answer

~60 s

Both let an algorithm's variable parts plug in, but the mechanism differs. Template Method uses **inheritance**: the skeleton lives in an abstract base class and subclasses override abstract primitives; the wiring is fixed at compile time and a subclass is bound to one skeleton. Strategy uses **composition**: the algorithm holds a reference to a strategy object (often a functional interface / lambda in modern Java) and delegates the variable step to it; that strategy can be swapped at run time. Template Method is simpler and keeps shared state easily accessible, but it couples each variant to the base class and you can't change behavior per-instance after construction. Strategy is more flexible, testable, and avoids class explosion, at the cost of passing collaborators and exposing the needed state. Modern Java often replaces Template Method's primitives with injected functions (Consumer, Function), blurring the line. Rule of thumb: use Template Method for a stable algorithm with a fixed, small set of variation points; use Strategy when variations are numerous, swappable at run time, or shared across unrelated algorithms.

go deeper

for a junior

Can say Template Method uses a subclass and Strategy passes in an object, and that Strategy is more flexible.

for a middle

Lists concrete differences (inheritance vs composition, compile-time vs run-time) and gives a code sketch of each.

for a senior

Explains 'favor composition over inheritance', the fragile base class problem, class explosion, and when Template Method is still preferable (shared state, JDK skeletal classes).

for a principal

Frames the choice in terms of evolution/coupling, the modern lambda/default-method blur, testability and dependency-injection implications, and migration paths between the two.

## The shared goal Both patterns answer: *how do I keep an algorithm's fixed structure while letting one or more steps vary?* They differ in **how** the variable part is supplied. ## Template Method — variation by inheritance - The fixed algorithm (skeleton) is a concrete method in an **abstract base class**. - Variation points are **abstract (or hook) methods**; a **subclass** overrides them. - Binding happens at **compile time / construction**: an instance *is* a particular subclass, so its behavior is fixed for its lifetime. - The base and subclass share the same `this`, so the subclass's overridden step has direct access to protected base state. ```java abstract class Sorter { final void sort(int[] a) { /* fixed loop */ if (less(a[i], a[j])) swap(); } protected abstract boolean less(int x, int y); // varied by subclass } ``` ## Strategy — variation by composition - The algorithm holds a **reference** to a separate **strategy object** implementing an interface. - The variable step is delegated to that object: `comparator.compare(x, y)`. - Binding happens at **run time**: you can pass a different strategy per instance, or even swap it later. - In modern Java the strategy is frequently a **lambda** against a functional interface (e.g. `Comparator`, `Function`, `Predicate`). ```java class Sorter { private final IntComparator cmp; // strategy (composition) Sorter(IntComparator cmp) { this.cmp = cmp; } void sort(int[] a) { if (cmp.less(a[i], a[j])) swap(); } } new Sorter((x, y) -> x < y); // swap behavior at runtime ``` ## Side-by-side | Aspect | Template Method | Strategy | |---|---|---| | Mechanism | Inheritance (override) | Composition (delegate) | | Binding time | Compile time / construction (fixed) | Run time (swappable) | | Unit of variation | A subclass | An object / lambda | | Multiple variations per object | No (one subclass) | Yes (different strategies) | | Access to algorithm's state | Direct (shared `this`) | Must be passed in | | Class count | One per variant (can explode) | One strategy per behavior, reusable | | Reuse across algorithms | No | Yes (same strategy in many contexts) | ## Why "favor composition over inheritance" The well-known guidance (Gang of Four; *Effective Java* Item 18) is to prefer composition because inheritance: - **Couples** the subclass to the base class's implementation details; a base-class change can silently break subclasses (the *fragile base class* problem). - Is **static** — you can't change a subclass's identity at run time. - Causes **class explosion** when variations multiply (a subclass per combination). - Breaks **encapsulation** — the base exposes protected internals to subclasses. Strategy avoids these: behaviors are independent objects, swappable, individually testable, and reusable across unrelated algorithms. ## When Template Method is still the right choice - The algorithm is **stable** with a **small, fixed** set of variation points that naturally belong together. - The variable steps need **easy access to shared state/protected helpers** of the algorithm — passing all that into a strategy would be awkward. - You want the **compiler to force** subclasses to supply mandatory steps (abstract methods do this; a strategy can be forgotten or null). - The JDK's skeletal collection classes are the poster child: `AbstractList`'s reuse of `get`/`size` is cleaner as inheritance than as a pile of injected functions. ## The modern blur Java 8 lambdas and `java.util.function` make Strategy nearly free, so many former Template Method designs are now "inject a `Consumer`/`Function` for the variable step." You also have **default methods** on interfaces, which can host a skeleton without an abstract class — a middle ground. The practical decision: *one cohesive algorithm with a couple of fixed hooks and shared state → Template Method; many interchangeable behaviors, runtime swapping, or cross-cutting reuse → Strategy.*

  • What is the 'fragile base class' problem and how does Strategy avoid it?
    When a subclass depends on the base class's internal implementation, a seemingly safe change to the base can break subclasses. Strategy avoids it because behaviors are separate objects interacting through a small interface, not through inherited internals.
  • Can you convert a Template Method design into a Strategy one, and what's the trade-off?
    Often yes — replace each abstract primitive with an injected functional interface. You gain runtime swappability and testability but must thread the algorithm's needed state through the strategy's parameters, and you lose the compiler-forced 'you must implement this step.'

saying these in an interview costs you the question

  • Claiming the two patterns are interchangeable with no trade-offs — binding time, state access, and class count differ.
  • Saying Strategy uses inheritance or Template Method uses composition (reversed).
  • Asserting inheritance is always wrong; Template Method is the right tool for stable algorithms with shared protected state, as the JDK shows.

context