Strategy turns an algorithm into a pluggable object. Instead of `if (kind === 'fifo') ...; else if (kind === 'lifo') ...`, you define a `QueueingStrategy` interface and inject a concrete one. The caller stays the same; the behavior changes. This is how you avoid `switch` statements that grow forever, and the canonical way to satisfy Open/Closed.
Whenever the same problem can be solved by multiple interchangeable algorithms and the choice depends on input, configuration, or A/B test bucket. Common in compression (gzip vs zstd), pricing (regular vs sale vs bulk), authentication (password vs OAuth vs SSO), routing (round-robin vs least-conn vs hash-based), and retry policies.
Try it
The pattern in code
interface SortStrategy<T> { sort(items: T[]): T[]; }
class QuickSort<T> implements SortStrategy<T> { sort(items: T[]) { /* ... */ } }
class MergeSort<T> implements SortStrategy<T> { sort(items: T[]) { /* ... */ } }
class TimSort<T> implements SortStrategy<T> { sort(items: T[]) { /* ... */ } }
class Pipeline<T> {
constructor(private strategy: SortStrategy<T>) {}
process(items: T[]) { return this.strategy.sort(items); }
}
// Pick at runtime — same Pipeline, different behavior.
const fast = new Pipeline(new QuickSort());
const stable = new Pipeline(new MergeSort());
Why it matters in system design
The classic “if/else jungle” is what Strategy was invented to kill. Picture a load balancer:
if (mode === 'rr') ... 30 lines ...
else if (mode === 'least_conn') ... 40 lines ...
else if (mode === 'p2c') ... 25 lines ...
else if (mode === 'hash') ... 35 lines ...
A new mode forces a code change in this one giant function. Tests have to cover every branch. The cyclomatic complexity is unbounded.
Strategy vs State — same shape, opposite intent
Strategy in distributed systems
Strategy shows up everywhere supply meets demand:
- Load balancing — round-robin, least-connections, weighted, P2C
- Partitioning — hash, range, consistent hashing
- Retry policies — no-retry, fixed, exponential backoff with jitter
- Serialization formats — JSON, Protobuf, Avro
- Cache eviction — LRU, LFU, TTL
All of these are Strategy implementations chosen via config.
Strategy + Factory = real systems
Trade-offs
Pros: Open/Closed compliant; each algorithm is independently testable; easy A/B test rollout; zero switch growth.
Comments 0
Discuss this page. Markdown supported. Be kind.