Strategy Pattern

Strategy Pattern

Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

Intent

The Strategy pattern extracts each variant algorithm into its own class behind a common interface. The Context holds a reference to a Strategy and delegates execution to it. The client (or the Context itself) calls setStrategy() to swap the algorithm at runtime. No concrete strategy class ever changes the Context's strategy reference — that swap is always external. This is the defining difference from the State-Pattern where the State object drives its own transitions.

When NOT to Use

  • Only one algorithm exists and will never vary — Strategy is premature abstraction with no payoff
  • The client never needs to change strategies at runtime — a direct method call is simpler
  • The number of potential strategies is small and fixed — use a simple enum switch, which is more readable
  • Strategies need access to private Context state — this breaks encapsulation and signals the algorithm should live inside the Context

When to Use

  • Multiple interchangeable algorithms exist for the same behaviour (sort, compress, validate, price)
  • Algorithm choice depends on runtime conditions (user config, environment, input characteristics)
  • You want to eliminate conditional logic that selects an algorithm (if type == 'quick' ... else if type == 'merge')
  • Open/closed principle priority — new algorithms must be addable without modifying the Context

How It Works

Participants:

  • Strategy — interface declaring the algorithm method (e.g., sort(data: number[]): number[]).
  • ConcreteStrategy — a specific algorithm implementation (QuickSort, BubbleSort, MergeSort). Never touches the Context's strategy reference.
  • Context — holds a Strategy reference, exposes setStrategy(s: Strategy) for runtime swapping, delegates execute() to the current strategy. The Context does not know which algorithm runs — it only knows the Strategy interface.

The client creates the Context with an initial Strategy and can call setStrategy() at any time to swap. The Context is oblivious to which algorithm is active.

Class Diagram

classDiagram
    class Context {
        -strategy : Strategy
        +setStrategy(s : Strategy)
        +executeStrategy(data)
    }
    class Strategy {
        <<interface>>
        +algorithm(data)*
    }
    class ConcreteStrategyA {
        +algorithm(data)
    }
    class ConcreteStrategyB {
        +algorithm(data)
    }
    class ConcreteStrategyC {
        +algorithm(data)
    }
    Context o-- Strategy : swappable at runtime
    Strategy <|.. ConcreteStrategyA
    Strategy <|.. ConcreteStrategyB
    Strategy <|.. ConcreteStrategyC

    note for Context "Delegates algorithm to\nthe current Strategy object.\nSwap point: setStrategy()"

TypeScript Example

// Strategy Pattern — TypeScript
// Source: GoF Design Patterns, p.315
 
interface SortStrategy {
  sort(data: number[]): number[];
}
 
class QuickSort implements SortStrategy {
  sort(data: number[]) {
    console.log("QuickSort applied");
    return [...data].sort((a, b) => a - b);  // simplified
  }
}
 
class BubbleSort implements SortStrategy {
  sort(data: number[]) {
    console.log("BubbleSort applied");
    return [...data].sort((a, b) => a - b);  // simplified
  }
}
 
class SortContext {  // Context
  constructor(private strategy: SortStrategy) {}
  setStrategy(s: SortStrategy) { this.strategy = s; }
  execute(data: number[]) { return this.strategy.sort(data); }
}
 
const ctx = new SortContext(new QuickSort());
ctx.execute([3, 1, 2]);          // QuickSort applied
ctx.setStrategy(new BubbleSort());
ctx.execute([3, 1, 2]);          // BubbleSort applied

Java Example

// Strategy Pattern — Java
// Source: GoF Design Patterns, p.315
 
interface SortStrategy {
    int[] sort(int[] data);
}
 
class QuickSort implements SortStrategy {
    public int[] sort(int[] data) {
        System.out.println("QuickSort applied");
        return data;  // simplified
    }
}
 
class BubbleSort implements SortStrategy {
    public int[] sort(int[] data) {
        System.out.println("BubbleSort applied");
        return data;  // simplified
    }
}
 
class SortContext {  // Context
    private SortStrategy strategy;
    public SortContext(SortStrategy s) { this.strategy = s; }
    public void setStrategy(SortStrategy s) { this.strategy = s; }
    public int[] execute(int[] data) { return strategy.sort(data); }
}

Lineage Forward

Strategy → Feature Flags lineage:

The Strategy pattern is the upstream ancestor of the Feature-Flags-Pattern (created Phase 15). Feature Flags implement Strategy at deployment level: the "strategy" (feature variant A or B) is selected at runtime via a flag, enabling Canary releases and A/B testing without code deployment. The lineage: Strategy → Feature Flags → Canary-Release-Pattern (Phase 15) → Blue-Green-Deployment (Phase 15).

PatternRelationship
State-PatternStructural twin — the key difference is who controls algorithm/transition selection; see the comparison callout in the State-Pattern note
Template-Method-PatternTemplate Method uses inheritance for variation; Strategy uses composition — prefer Strategy when the algorithm must be swappable at runtime
Command-PatternCommand encapsulates a specific request with receiver binding; Strategy encapsulates a reusable algorithm without receiver binding
  • Component-Composition-Patterns — Custom hooks in React implement Strategy: useForm() or useAuth() are interchangeable behaviour units injected into a component without changing the component's structure. Angular's inject() function achieves the same Strategy/Factory composition via the DI system.
  • State-Management-Patterns — Swapping between Flux/Redux, Signals, and Atomic store paradigms is Strategy applied to state management: each paradigm is an interchangeable algorithm for the same problem (state updates propagating to UI).

Sources

  • Gamma, Helm, Johnson, Vlissides — Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, p.315

Notes that link here: GoF-Patterns-MOC