Every site that constructs a UI widget switches on theme — and adding a new theme means hunting every switch and adding a new branch in lockstep. One missed branch silently produces a half-themed UI that ships looking 'mostly right' until a designer or QA notices. The team's verification cost and comprehension cost both compound across every switch site.
The agent scans multiple call sites to verify theme consistency on any UI-construction edit. Type-tag dispatch on theme is structurally invisible — from one site the agent cannot tell whether sibling sites have been kept in sync. The agent's context-window load multiplies across the call-site population, and the retrieval cost of finding each sibling site is per-edit overhead.
A factory interface that produces a coherent family of widgets, with concrete factories enforcing family-internal consistency. Client code receives a factory and asks for products; it never names the concrete class and cannot mix widgets across themes by accident, supporting separation of concerns between client logic and family selection.
The agent reads one factory interface to know what products exist; concrete factories are short and exhaustive; client code is one factory pointer away from the right family. The agent's context window holds the factory interface; the reasoning step count drops because cross-call-site family consistency becomes structurally guaranteed rather than inspection-required.
Before the pattern
function renderToolbar(theme) {let button;let textField;if (theme === 'light') {button = new LightButton();textField = new LightTextField();} else if (theme === 'dark') {button = new DarkButton();textField = new DarkTextField();} else {throw new Error(`unknown theme: ${theme}`);}return [button, textField];}
After the pattern
class LightWidgetFactory {createButton() { return new LightButton(); }createTextField() { return new LightTextField(); }}class DarkWidgetFactory {createButton() { return new DarkButton(); }createTextField() { return new DarkTextField(); }}function renderToolbar(factory) {return [factory.createButton(), factory.createTextField()];}
Theme dispatch is Shotgun Surgery at every construction site. The type system has no way to enforce that all widgets in one render path belong to the same theme — that invariant lives in convention and reviewer attention, both of which erode under deadline pressure. The blast radius of any theme edit stretches into every render path.
N call sites × M theme branches = N×M cells the agent verifies on every theme-related edit. Adding a theme forces the agent to find every switch and prove no branch was missed. The agent's verification-surface cost multiplies with N×M, and a partial update produces a half-themed UI the type checker cannot catch.
The factory interface and concrete subfactories grow in lockstep with the product set. Every new product method must be implemented across every concrete factory. Adding one product becomes a one-place-times-N change instead of a one-place change, and the team's maintenance cost per product addition multiplies with the number of factories.
A new product method requires the agent to update every concrete factory in lockstep. The factory interface becomes a single mutation surface the agent reads fully before any product edit; partial knowledge produces compile errors that surface late in the iteration cycle. The agent's completeness-check cost on product additions multiplies with the count of concrete factories.
Client code reads as `factory.createButton(); factory.createTextField()` regardless of theme. New theme = one new concrete factory; products in one render path are family-coherent by construction; the linter or the type system catches missing factory methods at compile time, not at user-visible runtime. The team's enhancement cost drops because new themes add one file rather than N call-site edits.
Adding a new family of products is one new factory implementation; the type checker confirms every factory produces the full family. The agent's token cost per family addition drops because the existing call-site population stays unchanged, and type-checker visibility of missing methods catches partial updates at compile time rather than runtime.
The factory interface accretes product methods over time and becomes a god interface. Sub-families with optional products (e.g., one theme has a DateRangePicker, another doesn't) force either NotImplemented throws or interface segregation — both costlier than the original switch and harder to undo. The cure adds accidental complexity when the interface stops describing one coherent family.
The factory interface accretes product methods over time — over many edits the agent cannot enumerate which products are still in use. Dead factory methods accumulate; cleanup requires touching every concrete factory in lockstep, exactly the cross-cutting edit the pattern was supposed to eliminate. Context-window load on the interface file grows monotonically as the product set drifts.