Intent
Intent: One-line statement of the pattern’s purpose — what it does and the problem it solves.
Example: “Define a family of algorithms, encapsulate each one, and make them interchangeable.”
Problem / Context
Describe when to use the pattern, the forces at play, constraints, and concrete symptoms that indicate the pattern is appropriate.
When to use
- Varying algorithms or behaviors at runtime
- Avoiding long conditional branching
- Decoupling clients from concrete implementations
Context examples
- UI behavior selection
- Multiple sorting/compression strategies
- Interchangeable payment processors
Solution (Plain Words)
Short description of the core idea and what responsibilities it moves or stabilizes.
Example summary: Introduce an abstraction for the behavior; implement concrete behaviors; let the client hold a reference to the abstraction and delegate.
Structure
Sketch the main elements and relationships.
Key participants: Context, Strategy (interface), ConcreteStrategy(s).
Participants / Responsibilities
- Context
- Maintains a reference to a Strategy and delegates requests to it.
- Strategy
- Defines the algorithm interface (method signatures).
- ConcreteStrategy
- Implements the algorithm defined by Strategy.
Collaborations / Dynamics
Describe the runtime flow in steps:
- Client configures Context with a ConcreteStrategy instance.
- Client invokes Context.operation(); Context delegates to Strategy.execute().
- ConcreteStrategy performs algorithm and returns result to Context/Client.
Consequences
Benefits
- Decouples client from concrete algorithm implementations.
- Makes algorithms interchangeable at runtime.
- Improves testability — each strategy can be unit-tested.
Costs / Tradeoffs
- More classes / objects, added indirection.
- Potential performance overhead from delegation.
- Can be overkill for trivial cases.
Applicability / When Not To Use
Use when: You need to vary behavior at runtime or avoid sprawling conditional logic.
Avoid when: A single algorithm suffices or the pattern adds unnecessary complexity.
Implementation Notes & Variants
- Prefer composition (Context has-a Strategy) over inheritance.
- In functional languages, use functions/closures instead of objects.
- If strategies share heavy state, consider Flyweight for memory efficiency.
Sample Code — Strategy (JavaScript)
// Strategy interface (implicit)
// Concrete strategies implement execute(input)
class Context {
constructor(strategy) { this.strategy = strategy; }
setStrategy(s) { this.strategy = s; }
doWork(data) { return this.strategy.execute(data); }
}
const StrategyA = { execute: (x) => `A:${x}` };
const StrategyB = { execute: (x) => `B:${x}` };
// Usage
const ctx = new Context(StrategyA);
console.log(ctx.doWork('payload')); // "A:payload"
ctx.setStrategy(StrategyB);
console.log(ctx.doWork('payload')); // "B:payload"
Replace JS objects with classes or functions in your target language as needed.
Known Uses / Examples
- Sorting algorithms (strategy = sort routine)
- Payment processors (strategy = payment gateway adapter)
- Compression or encryption selection
Related Patterns
Complementary: Factory (creates strategies), Dependency Injection (supplies strategies). Contrasting: State (when behavior depends on internal state transitions rather than a pluggable algorithm).
Refactoring Steps (Converting existing code)
- Identify conditional branches selecting algorithms.
- Introduce a Strategy abstraction (interface or signature).
- Extract each branch into a ConcreteStrategy implementation.
- Inject the chosen strategy into the Context and update clients.
- Write tests for each strategy and the Context integration.
Testing & Verification
- Unit-test each ConcreteStrategy independently.
- Mock strategies when testing Context behavior.
- Benchmark if strategies will run in tight loops (performance-sensitive).

Leave a Reply