principle-design-patterns · git:20260828.71a6399 · 2026-08-28 · sha256 aae11f626f58dae7
principle-design-patterns git:20260828.71a6399A
Immutable. This exact content never changes and is served at /api/v1/blob/aae11f626f58dae7.
--- name: principle-design-patterns description: Design patterns — Gang of Four and beyond. Strategy, factory method, observer, adapter, template method, dependency injection. Auto-load when designing class structure, or evaluating whether a pattern applies. --- <!-- preload-canary: SWB-PRELOAD-PRINCIPLE-DESIGN-PATTERNS --> # Design Patterns — the ones worth knowing Patterns are vocabulary, not goals. Reach for one only when the problem it solves is actually present. ## Strategy **Problem:** an algorithm varies independently of its caller. **Use when:** multiple interchangeable behaviors selected at runtime (pricing rules, compression, sort orders). **Overkill when:** there is only one strategy. **Modern alternative:** a first-class function or lambda. ## Factory Method **Problem:** construction is non-trivial or must be swappable. **Use when:** the concrete type depends on input or config. **Overkill when:** `new Thing()` works and always will. **Modern alternative:** a constructor function plus DI at the composition root. ## Observer **Problem:** many objects need to react to a state change. **Use when:** loose coupling between emitter and listeners (UI, domain events). **Overkill when:** one listener, ever — call it directly. **Modern alternative:** language-native events, reactive streams, domain events on a bus. ## Decorator **Problem:** add behavior without subclassing the world. **Use when:** stacking optional behavior — caching, logging, retries around a core call. **Overkill when:** no composition, one behavior. **Modern alternative:** middleware chains, higher-order functions. ## Adapter **Problem:** two interfaces should work together but don't. **Use when:** integrating a third-party or legacy API into your domain types. **Overkill when:** you control both sides — just change one. ## Facade **Problem:** a subsystem has too many moving parts for its callers. **Use when:** simplifying a complex API for the common 80%. **Overkill when:** the facade just forwards one call. ## Template Method **Problem:** the skeleton of an algorithm is fixed but steps vary. **Use when:** several variants share a clear sequence. **Overkill when:** the sequence is two steps. **Warning:** easy to abuse — prefer Strategy when steps are independent. ## Command **Problem:** parameterize, queue, log, or undo actions. **Use when:** task queues, undo/redo, transactional operations. **Overkill when:** you just want to call a function. ## Repository **Problem:** domain code should not depend on storage details. **Use when:** persisting aggregates behind a collection-like interface. **Overkill when:** a single SQL query in a single place. ## Dependency Injection (essential, not GoF) **Problem:** classes that new-up their own collaborators are untestable and rigid. **Use when:** wiring side-effecting collaborators (clocks, IDs, repositories, gateways). **Overkill when:** constructing simple value objects. **Anti-pattern:** heavyweight DI frameworks for small apps — constructor injection at `main()` is usually enough. ## Anti-patterns worth naming - **Singleton** — almost always a disguised global; prefer a single instance composed at the root. - **God object** — one class that does everything; split by change vector. - **Pattern-itis** — five patterns where a function would do. > See `examples/` for worked Strategy, Observer, Decorator, and Factory Method implementations in C#, Go, Java, Kotlin, Python, Ruby, Rust, Swift, and TypeScript (read on demand — not auto-loaded).