| name | design-patterns |
| description | Use when designing software architecture, refactoring code structure, solving recurring design problems, or when code exhibits symptoms like tight coupling, rigid hierarchies, scattered responsibilities, or difficult-to-test components. Also use when choosing between architectural approaches or reviewing code for structural improvements. |
Design Patterns
Overview
Design patterns are proven solutions to recurring software design problems. They provide a shared vocabulary for discussing design and capture collective wisdom refined through decades of real-world use.
Core Philosophy: Patterns are templates you adapt to your context, not blueprints to copy. Use the right pattern when it genuinely simplifies your design—not to impress or over-engineer.
Foundational Principles
These principles underpin all good design:
| Principle |
Meaning |
Violation Symptom |
| Encapsulate What Varies |
Isolate changing parts from stable parts |
Changes ripple through codebase |
| Program to Interfaces |
Depend on abstractions, not concretions |
Can't swap implementations |
| Composition Over Inheritance |
Build behavior by composing objects |
Deep rigid class hierarchies |
| Loose Coupling |
Minimize interdependency between objects |
Can't change one thing without breaking another |
| Open-Closed |
Open for extension, closed for modification |
Must edit existing code for new features |
| Single Responsibility |
One reason to change per class |
Classes doing too many things |
| Dependency Inversion |
High-level modules don't depend on low-level |
Business logic coupled to infrastructure |
Pattern Selection Guide
By Problem Type
CREATING OBJECTS
├── Complex/conditional creation ──────────→ Factory Method
├── Families of related objects ───────────→ Abstract Factory
├── Step-by-step construction ─────────────→ Builder
├── Clone existing objects ────────────────→ Prototype
└── Single instance needed ────────────────→ Singleton (use sparingly!)
STRUCTURING/COMPOSING OBJECTS
├── Incompatible interface ────────────────→ Adapter
├── Simplify complex subsystem ────────────→ Facade
├── Tree/hierarchy structure ──────────────→ Composite
├── Add behavior dynamically ──────────────→ Decorator
└── Control access to object ──────────────→ Proxy
MANAGING COMMUNICATION/BEHAVIOR
├── One-to-many notification ──────────────→ Observer
├── Encapsulate requests as objects ───────→ Command
├── Behavior varies by internal state ─────→ State
├── Swap algorithms at runtime ────────────→ Strategy
├── Algorithm skeleton with hooks ─────────→ Template Method
├── Reduce N-to-N communication ───────────→ Mediator
└── Sequential handlers ───────────────────→ Chain of Responsibility
MANAGING DATA ACCESS
├── Abstract data source ──────────────────→ Repository
├── Track changes for atomic commit ───────→ Unit of Work
├── Ensure object identity ────────────────→ Identity Map
├── Defer expensive loading ───────────────→ Lazy Load
├── Map objects to database ───────────────→ Data Mapper
└── Shape data for transfer ───────────────→ DTO
By Symptom
| Symptom |
Consider |
| Giant switch/if-else on type |
Strategy, State, or polymorphism |
| Duplicate code across classes |
Template Method, Strategy |
| Need to notify many objects of changes |
Observer |
| Complex object creation logic |
Factory, Builder |
| Adding features bloats class |
Decorator |
| Third-party API doesn't fit your code |
Adapter |
| Too many dependencies between components |
Mediator, Facade |
| Can't test without database/network |
Repository, Dependency Injection |
| Need undo/redo |
Command |
| Object behavior depends on state |
State |
| Request needs processing by multiple handlers |
Chain of Responsibility |
Domain Logic: Transaction Script vs Domain Model
| Factor |
Transaction Script |
Domain Model |
| Logic complexity |
Simple (< 500 lines) |
Complex, many rules |
| Business rules |
Few, straightforward |
Many, interacting |
| Operations |
CRUD-heavy |
Rich behavior |
| Team/timeline |
Small team, quick delivery |
Long-term maintenance |
| Testing |
Integration tests |
Unit tests on domain |
Rule of thumb: Start with Transaction Script. Refactor to Domain Model when procedural code becomes hard to maintain.
Quick Reference
Tier 1: Essential Patterns (Master First)
| Pattern |
One-Line |
When to Use |
Reference |
| Strategy |
Encapsulate interchangeable algorithms |
Multiple ways to do something, swap at runtime |
strategy.md |
| Observer |
Notify dependents of state changes |
Event systems, reactive updates |
observer.md |
| Factory |
Encapsulate object creation |
Complex/conditional instantiation |
factory.md |
| Decorator |
Add behavior dynamically |
Extend without inheritance |
decorator.md |
| Command |
Encapsulate requests as objects |
Undo/redo, queuing, logging |
command.md |
Tier 2: Structural Patterns
| Pattern |
One-Line |
When to Use |
Reference |
| Adapter |
Convert interfaces |
Integrate incompatible code |
adapter.md |
| Facade |
Simplify complex subsystems |
Hide complexity behind simple API |
facade.md |
| Composite |
Uniform tree structures |
Part-whole hierarchies |
composite.md |
| Proxy |
Control access to objects |
Lazy load, access control, caching |
proxy.md |
Tier 3: Enterprise/Architectural Patterns
| Pattern |
One-Line |
When to Use |
Reference |
| Repository |
Collection-like data access |
Decouple domain from data layer |
repository.md |
| Unit of Work |
Coordinate atomic changes |
Transaction management |
unit-of-work.md |
| Service Layer |
Orchestrate business operations |
Define application boundary |
service-layer.md |
| DTO |
Shape data for transfer |
API contracts, prevent over-exposure |
dto.md |
Additional Important Patterns
| Pattern |
One-Line |
When to Use |
Reference |
| Builder |
Step-by-step object construction |
Complex objects, fluent APIs |
builder.md |
| State |
Behavior changes with state |
State machines, workflow |
state.md |
| Template Method |
Algorithm skeleton with hooks |
Framework extension points |
template-method.md |
| Chain of Responsibility |
Pass request along handlers |
Middleware, pipelines |
chain-of-responsibility.md |
| Mediator |
Centralize complex communication |
Reduce component coupling |
mediator.md |
| Lazy Load |
Defer expensive loading |
Performance, large object graphs |
lazy-load.md |
| Identity Map |
Ensure object identity |
ORM, prevent duplicates |
identity-map.md |
Common Mistakes
| Mistake |
Symptom |
Fix |
| Pattern Overuse |
Simple operations require navigating many classes |
Only use when solving real problem |
| Wrong Pattern |
Code feels forced, awkward |
Re-examine actual problem |
| Inheritance Abuse |
Deep hierarchies, fragile base class |
Favor composition (Strategy, Decorator) |
| Singleton Abuse |
Global state, hidden dependencies, hard to test |
Use dependency injection instead |
| Premature Abstraction |
Interfaces with single implementation |
Wait for real need to vary |
Anti-Patterns to Recognize
- God Object: One class does everything → Split using SRP
- Anemic Domain Model: Objects are just data bags → Move behavior to objects
- Golden Hammer: Same pattern everywhere → Match pattern to problem
- Lava Flow: Dead code nobody removes → Delete it, VCS has your back
Modern Variations
| Modern Pattern |
Based On |
Description |
| Dependency Injection |
Strategy + Factory |
Container creates and injects dependencies |
| Middleware |
Decorator + Chain of Responsibility |
Request/response pipeline |
| Event Sourcing |
Command |
Store state changes as events |
| CQRS |
Command/Query separation |
Separate read/write models |
| Hooks (React/Vue) |
Observer + Strategy |
Functional lifecycle subscriptions |
Implementation Checklist
Before implementing a pattern: