skip to content

Compare Strategy with Template Method and with Bridge: what does each vary, by what mechanism, and how do you choose between them?

level: seniorimportance: should knowfreq 34%

answer

  1. Template Method = inheritance, steps in a fixed skeleton
  2. Strategy = composition, whole algorithm, runtime
  3. Bridge = two hierarchies, M+N not M×N
  4. fragile base class vs. wiring cost
  5. hybrid: skeleton in context, steps injected

basics

~20 s

Strategy swaps a whole algorithm via composition, chosen at runtime. Template Method fixes the algorithm's skeleton in a base class and lets subclasses override individual steps, bound at compile time by inheritance. Bridge splits an abstraction hierarchy from an implementation hierarchy so both can grow independently.

solid answer

~60 s

**Template Method** (class-based): an abstract base defines the invariant sequence and calls abstract/overridable hook steps; subclasses supply the varying steps. Reuse of the skeleton is the point. Costs: binding is static, it consumes the single inheritance slot, and the base–subclass coupling is tight (the *fragile base class* problem, plus hooks that must not be called out of order). **Strategy** (object-based): the whole varying operation lives in a separate object injected into the context; selectable and replaceable at runtime, testable alone, reusable across contexts, and stackable via decoration. **Bridge**: structural rather than behavioral. It separates two dimensions that would otherwise multiply into a subclass explosion — an `Abstraction` hierarchy (refined independently) delegating to an `Implementor` hierarchy. Structurally it resembles Strategy, but the intent is to keep two *hierarchies* orthogonal for the life of the design, not to swap one algorithm. Choose Template Method when steps vary inside a fixed skeleton you own; Strategy when the whole operation varies and should be chosen at runtime; Bridge when two independent axes of variation would otherwise cross-multiply.

go deeper

for a junior

Contrast the mechanisms: Template Method uses inheritance and overrides steps; Strategy passes in an object with the whole algorithm and can change at runtime.

for a middle

Add binding time, testability, single-inheritance limits, and the composed hybrid where the context keeps the skeleton and injects each step.

for a senior

Bring in the fragile base class problem, constructor-time hook calls, when to migrate Template Method to Strategy, and Bridge's M+N argument versus Strategy's per-request selection.

for a principal

Discuss binding time and ownership as the real decision axes — who may add variants, whether the contract is published to other teams, and the long-term cost of an inherited skeleton as an unpublished API surface.

## Vocabulary first - **Inheritance** — a subclass reuses and specializes a base class; the binding is fixed when the object is created and cannot change afterwards. - **Composition** — an object holds a reference to a collaborator and delegates; the collaborator can be chosen or replaced at runtime. - **Hook method** — an abstract or overridable method called by a base-class algorithm at a defined point. - **Combinatorial explosion** — when two independent axes of variation are modeled by subclassing, you need M × N classes (`WindowsCircle`, `LinuxCircle`, `WindowsSquare`, …). ## Template Method *Intent*: define the skeleton of an algorithm in an operation, deferring some steps to subclasses; subclasses redefine steps without changing the algorithm's structure. ``` abstract class Importer { final run(source) { // the invariant skeleton, deliberately not overridable raw = read(source) // hook parsed = parse(raw) // hook validate(parsed) // shared, fixed persist(parsed) // hook } protected abstract read(s); protected abstract parse(r); protected abstract persist(p) } ``` *Use it when*: the sequence is genuinely invariant and worth enforcing, the variation is *within* steps, and you control the base class. It gives maximum code reuse of the skeleton with minimum boilerplate. *Costs*: the variant is chosen when you pick the class, so no runtime swapping; only one skeleton can be inherited (single inheritance in most languages); the base–subclass contract is implicit and easy to break — the *fragile base class* problem, where a change in the base silently breaks subclasses you can't see; subclasses can be tempted to override the skeleton itself; a subclass overriding a hook that the base calls during construction is a classic initialization bug; and testing a step usually means instantiating the whole subclass. *The Strategy equivalent ("prefer composition")*: convert each hook into an injected collaborator — `Importer(reader, parser, persister)`. Now steps are independently testable and mixable, at the cost of more wiring. This is exactly why many codebases migrate Template Method → Strategy as the family grows. ## Strategy *Intent*: define a family of interchangeable algorithms behind one interface so the algorithm varies independently of clients. Differences from Template Method that matter in practice: | | Template Method | Strategy | |---|---|---| | Mechanism | Inheritance | Composition/delegation | | Bound | Compile time (class choice) | Runtime (injected value) | | Varies | Steps inside a fixed skeleton | The whole operation | | Reuse of skeleton | Automatic (base class) | Manual (context or a shared collaborator) | | Testability of a variant | Needs the subclass + base | Variant alone | | Multiple axes | Combinatorial subclasses | Multiple injected strategies | | Extensible by others | Only by subclassing your base | By implementing a published interface | *Hybrid*: a Context that owns the skeleton and delegates each step to an injected strategy is Template Method's intent implemented with Strategy's mechanism — common and usually the better default when the number of variants grows. ## Bridge *Intent*: decouple an abstraction from its implementation so the two can vary independently. ``` abstract class Shape(renderer: Renderer) { abstract draw() } // Abstraction class Circle(r: Renderer): Shape(r) { draw() = r.drawCircle(...) } // RefinedAbstraction interface Renderer { drawCircle(...); drawRect(...) } // Implementor class SvgRenderer / CanvasRenderer implements Renderer // ConcreteImplementor ``` Without Bridge you'd write `SvgCircle`, `CanvasCircle`, `SvgRect`, `CanvasRect` — M × N. With Bridge you write M + N. *How it differs from Strategy despite the similar picture*: - Strategy's context is typically **one class** with a **pluggable algorithm**; Bridge's abstraction is itself a **hierarchy** that grows alongside the implementor hierarchy. - Strategy's implementations are *alternative solutions to the same task*, often switched per call/request. Bridge's implementors are *platform/backend layers* usually fixed for the lifetime of the object. - Strategy interfaces are usually one operation; Bridge implementors expose a primitive-operations API the abstraction composes into higher-level behavior. - Strategy is behavioral (how work gets done); Bridge is structural (how types are composed). ## Choosing 1. Is the *sequence* fixed and only steps vary, and do you own and control the base class with few variants? → **Template Method** (or its composed hybrid). 2. Does the *whole operation* vary, must the choice be made at runtime/config/tenant, or do you want outside code to add variants? → **Strategy**. 3. Are there *two independent axes* (domain concept × backend/platform) that would cross-multiply into subclasses? → **Bridge**. 4. Is the variation a *value* rather than an algorithm? → a lookup table, not a pattern. Also in the neighborhood: **Decorator** wraps a strategy to add behavior (caching, metrics, retries) while keeping the interface; **Chain of Responsibility** tries handlers in order rather than selecting one; **State** looks like Strategy but is lifecycle-driven; **Visitor** varies operations over a fixed set of types instead of varying one operation. A final practical note: these are communication labels. What matters in a design discussion is naming *which axis varies*, *when it is bound*, and *who is allowed to add a variant* — the pattern name is shorthand for those three answers.

  • How do you convert a Template Method design to Strategy?
    Turn each abstract hook into an interface, inject implementations into the former base class (now a concrete context that owns the skeleton), and delete the subclasses. You gain runtime selection, independent testing, and free mixing of steps; you pay in explicit wiring and more types.
  • Isn't Bridge just Strategy with a nicer name?
    The class picture is similar, but Bridge's defining feature is that *both* sides are hierarchies varying independently for the life of the design, and the implementor exposes primitive operations the abstraction composes. Strategy has one context and interchangeable, often per-request algorithms.
  • What is the 'fragile base class' problem and how does Strategy avoid it?
    Subclasses depend on unpublished details of the base — call order, which methods invoke which — so an innocuous base change breaks them invisibly. Strategy replaces that implicit contract with an explicit interface and a delegation boundary, so the only coupling is the declared signature.

Template Method is a franchise recipe card: the steps and their order are printed, and each branch fills in the local ingredient. Strategy is hiring whichever chef you like for tonight's dish. Bridge is separating the menu from the kitchen equipment so new dishes and new appliances don't multiply against each other.

saying these in an interview costs you the question

  • Calling every delegation to an interface 'Strategy' without asking whether two hierarchies are varying (Bridge) or a lifecycle is driving it (State).
  • Claiming Template Method is obsolete; for a genuinely fixed skeleton with two or three variants it is the least ceremony.
  • Overriding the template method itself in a subclass, destroying the invariant the pattern exists to enforce.
  • Calling an overridable hook from a base-class constructor, so it runs before the subclass is initialized.
  • Saying Bridge is about hiding implementation details — that is encapsulation generally; Bridge is specifically about avoiding M × N class growth across two axes.

context