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.
Algorithm-specific code lives inside a host class with type-tag dispatch the agent must read to understand variant behaviour. Adding an algorithm requires the agent to edit the host; the diff blast radius is unpredictable; per-algorithm tests require constructing the host's full graph.
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.
One strategy interface and N small implementations the agent reads independently. Per-algorithm verification is one-file-scoped; strategy selection is one expression at the construction site; the host's relevant method is a one-line delegation.
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.
Type-tag dispatch inside the host forces every algorithm-related edit to load the full host file with all dispatch branches; the per-edit context covers the host plus the active branch instead of one strategy class. Tests for one algorithm pull in the host's collaborator graph, multiplying setup cost per per-algorithm verification.
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.
N strategy classes is N files the agent navigates per algorithm-related task. Strategy interface design matters — extra optional methods bloat every implementation and force per-implementation no-op tests the agent must verify.
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.
Each strategy lives at one file the agent reads in isolation; adding a new algorithm is one new class implementing the strategy interface plus one construction-site edit, and the host class stays unchanged.
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.
Strategy interfaces with optional methods (some algorithms implement calibrate(), others do not) blur the contract. The agent must verify per-implementation interface completeness rather than reading the interface as a structural promise. Define one focused interface, or split the family by capability.