Symptom

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.

Goal

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);
Example source: Illustrative example written for this site in the spirit of Design Patterns (Gamma, Helm, Johnson, Vlissides, Addison-Wesley, 1994), chapter 5. The book uses a Composition class with line-breaking strategies; this JavaScript adaptation uses shipping-cost algorithms to make the family-of-interchangeable-formulas shape concrete without overlapping with Kerievsky's loan-calculator example for the same pattern.
Pressure

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.

Tradeoff

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.

Relief

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.

Trap

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.