Commissioned for this museum · after Gamma, Helm, Johnson & Vlissides, 1994
Strategy
TypeScript·1994·25 lines·705 bytes
/**
* Strategy — the part of an algorithm that varies, handed in rather than
* branched on.
*/
type Pricing = (weightKg: number) => number;
const standard: Pricing = (kg) => 4 + kg * 1.1;
const express: Pricing = (kg) => 9 + kg * 2.4;
const courtesy: Pricing = () => 0;
// The quote knows nothing about how a price is arrived at. Adding a fourth
// way to charge does not touch this function.
function quote(weightKg: number, pricing: Pricing): string {
return pricing(weightKg).toFixed(2);
}
const offers: [string, Pricing][] = [
["standard", standard],
["express", express],
["courtesy", courtesy],
];
for (const [name, pricing] of offers) {
console.log(`${name}: ${quote(2, pricing)}`);
}Curator’s note
The pattern is a single line: type Pricing = (weightKg: number) => number. Everything else in the file is a demonstration of what that line buys, which is the absence of a switch on a shipping-method string in the middle of quote.
In 1994 this was drawn as an interface with one method and a family of classes implementing it, and the drawing was the honest part — in a language without first-class functions, a one-method interface *is* how you pass behaviour around. Give the language closures and the ceremony evaporates: an interface with one method is a function type, and three classes become three declarations. Nobody writing this today would call it a pattern. They would call it an argument.
What survives the simplification is the design decision, which was never about classes. Somebody still has to notice that pricing varies, that quote should not know how, and that the variation belongs at the call site. That noticing is the whole pattern. The syntax it arrives in is incidental.
The cost is discoverability, and it is real. Three named strategies can be found, listed and tested; an anonymous arrow written inline at the call site cannot, and a codebase that has taken this pattern to heart tends to accumulate them. A class at least has to be declared somewhere you can grep for.