Start Learning
Javaneer
Back to stage
Stage 1·Design Patterns Applied

Strategy & Template Method

Behavioral patterns: strategy formalizes the interchangeable fee policies from Open/Closed; template method fixes an algorithm's skeleton while letting steps vary.

15 min readAdvanced
On this page

Two behavioral patterns handle the two ways an algorithm varies. Strategy swaps a whole algorithm at runtime - you already built it in the Open/Closed lesson without the name. Template Method fixes the algorithm's skeleton and lets subclasses vary only specific steps. Knowing which one a situation wants - replace the whole thing, or vary a few steps of a fixed sequence - is the skill.

Strategy: interchangeable whole algorithms

Strategy encapsulates a family of algorithms behind a common interface so they're interchangeable at runtime. This is exactly the FeePolicy design from Open/Closed, now named:

interface FeePolicy { BigDecimal fee(Transaction t); }         // the strategy interface

class FeeCalculator {
    private FeePolicy policy;                                    // the current strategy
    void setPolicy(FeePolicy p) { this.policy = p; }            // swap at runtime
    BigDecimal calculate(Transaction t) { return policy.fee(t); }
}

The defining trait: the entire algorithm is replaceable, and the choice can change at runtime (per transaction, per config, per A/B test). Strategy favors composition - the context has-a strategy - which is why it's so flexible. It's the go-to when behavior varies along one axis and you want it swappable.

Template Method: a fixed skeleton with variable steps

Sometimes the overall sequence is fixed and only certain steps differ. ledger-legacy generates every report the same way - open, write header, write rows, write footer, close - but the format of each step varies. That's Template Method: a base class defines the invariant skeleton in one method and defers the varying steps to subclasses:

abstract class ReportGenerator {
    // the TEMPLATE METHOD - fixed skeleton, not overridable
    public final String generate(List<Transaction> txns) {
        StringBuilder out = new StringBuilder();
        out.append(header());                         // step varies
        txns.forEach(t -> out.append(row(t)));        // step varies
        out.append(footer());                         // step varies
        return out.toString();
    }
    protected abstract String header();               // subclasses fill these in
    protected abstract String row(Transaction t);
    protected abstract String footer();
}

class CsvReportGenerator implements/extends ReportGenerator {   // only the steps differ
    protected String header() { return "date,amount,fee\n"; }
    protected String row(Transaction t) { return t.date() + "," + t.amount() + "\n"; }
    protected String footer() { return ""; }
}

The skeleton (generate) is written once and marked final so no subclass can reorder it; subclasses supply only header, row, footer. The sequence is guaranteed; the details vary.

Choosing between them

They look similar - both vary behavior - but differ in what varies and how:

StrategyTemplate Method
Variesthe whole algorithmsteps within a fixed skeleton
Mechanismcomposition (has-a)inheritance (is-a)
Swappable at runtime?yesno (fixed at compile time by subclass)
Couplingloosetighter (subclass bound to base)

Prefer Strategy when you want runtime swapping and looser coupling (the modern default). Reach for Template Method when there's a genuine fixed sequence whose steps vary and the base/subclass relationship is natural - but beware, it uses inheritance, so the LSP cautions apply.

Template Method's modern cousin

You can get Template Method's 'fixed skeleton, pluggable steps' without inheritance by passing the varying steps as functions/lambdas or a small strategy object - composition again. Many teams prefer this: generate(txns, headerFn, rowFn, footerFn) or a ReportFormat strategy. If you find Template Method forcing awkward inheritance, that's the nudge to refactor it into Strategy-style composition.

A recipe card vs. a set menu you swap wholesale

Template Method is a recipe card with fixed steps - 'prep, cook, plate, garnish, in that order' - where the cook fills in what to prep and how to garnish, but can't reorder the steps or skip plating. Strategy is choosing an entirely different dish for tonight: swap the whole 'make lasagna' algorithm for 'make curry' at will, no shared skeleton imposed. One says 'the sequence is sacred, vary the ingredients'; the other says 'here's a slot - drop in whichever complete method you like.'

Strategy, Template Method, or both?

ledger-legacy exports statements. Every export follows the same fixed steps (validate → render header → render each row → render footer → checksum), but the rendering format (PDF, CSV, JSON) varies, AND separately the business wants to swap the checksum algorithm (MD5 vs SHA-256) independently at runtime for compliance. How would you structure this?

What's the key difference between Strategy and Template Method?

Key takeaways

  • Both are behavioral patterns for varying an algorithm, but along different axes.
  • Strategy encapsulates interchangeable whole algorithms behind an interface, composed into a context and swappable at runtime (the FeePolicy design).
  • Template Method fixes the algorithm's skeleton in a final base method and defers only specific steps to subclasses.
  • Strategy uses composition (loose, runtime-swappable); Template Method uses inheritance (tighter, fixed by subclass) - so LSP cautions apply.
  • Prefer Strategy as the modern default; you can also get Template Method's pluggable steps via lambdas/composition instead of inheritance.
Was this lesson helpful?
Edit this page on GitHub