A family of algorithms varies along one dimension (cost formula, sorting key, cipher, retry policy) and lives as if/else branches inside a host class. Adding a new algorithm means editing the host; algorithms cannot be tested in isolation; the host accumulates algorithm-specific magic numbers.
Each algorithm is a small class implementing one operation method; the host holds a strategy reference and delegates. Algorithms are interchangeable at the construction site; new algorithms are new classes; the host stays unchanged.
Before the pattern
class Order {constructor(shippingType) {this.shippingType = shippingType;}shippingCost(weight, distance) {if (this.shippingType === 'standard') {return weight * 0.5 + distance * 0.01;} else if (this.shippingType === 'express') {return weight * 1.0 + distance * 0.02 + 5;} else if (this.shippingType === 'overnight') {return weight * 2.0 + distance * 0.05 + 15;}throw new Error(`unknown shippingType: ${this.shippingType}`);}}// Adding 'two-day' or 'international' = a new branch.// Testing one algorithm requires constructing a full Order.
After the pattern
class StandardShipping {calculate(weight, distance) {return weight * 0.5 + distance * 0.01;}}class ExpressShipping {calculate(weight, distance) {return weight * 1.0 + distance * 0.02 + 5;}}class OvernightShipping {calculate(weight, distance) {return weight * 2.0 + distance * 0.05 + 15;}}class Order {constructor(shippingStrategy) {this.shippingStrategy = shippingStrategy;}shippingCost(weight, distance) {return this.shippingStrategy.calculate(weight, distance);}}const order = new Order(new ExpressShipping());const cost = order.shippingCost(5, 200);
Algorithm dispatch inside the host is Repeated Switches at the worst level — every algorithm-related edit touches the host; every host edit risks affecting unrelated algorithms; tests of one algorithm require constructing the host's full collaborator set.
Each strategy lives in its own file; the class count grows with algorithm count; client code must choose a strategy at construction time, pushing the type-tag decision out of the host but not out of the system. Strategy interfaces that grow optional methods drift toward Template Method or a god interface.
Algorithms are unit-testable in isolation with synthetic inputs; new algorithms are PR-sized; the host's shippingCost reads as a one-line delegation. Pricing tweaks, formula corrections, and A/B-testing variants all stay scoped to one strategy file.
Strategies that need shared state (rate tables, currency conversion, calibration constants) and pull them through constructor parameters of every strategy reintroduce duplication. Often a thin shared-context object (Strategy + Context-object pair) restores the focus; otherwise strategy interfaces drift toward god-interface territory.