When to Use Which Pattern — A Decision Guide
Quick Reference
| Problem | Pattern | Category |
|---|---|---|
| Need exactly one global instance | Singleton | Creational |
| Create objects without specifying class | Factory | Creational |
| Complex object construction | Builder | Creational |
| Incompatible interface | Adapter | Structural |
| Add behavior without subclassing | Decorator | Structural |
| Simplify complex subsystem | Facade | Structural |
| Notify multiple objects of state change | Observer | Behavioral |
| Swap algorithms at runtime | Strategy | Behavioral |
| Encapsulate actions with undo support | Command | Behavioral |
| Pass request through handler chain | Chain of Responsibility | Behavioral |
| Coordinate async producers & consumers | Producer/Consumer | Concurrency |
| Protect calls to unreliable services | Circuit Breaker | Concurrency |
Decision Flowchart
START → Do you need to create objects?
│
├─ YES → Is construction complex (many optional params)?
│ ├─ YES → Builder
│ └─ NO → Do you need to decouple creation from usage?
│ ├─ YES → Factory
│ └─ NO → Do you need exactly one instance?
│ ├─ YES → Singleton
│ └─ NO → Plain constructor is fine
│
└─ NO → Do you need to add behavior?
├─ YES → Is it cross-cutting (logging, retry, caching)?
│ ├─ YES → Decorator
│ └─ NO → Do you need to swap behavior at runtime?
│ ├─ YES → Strategy
│ └─ NO → Standard subclassing
│
└─ NO → Do you need to handle events/actions?
├─ YES → Do multiple listeners need notification?
│ ├─ YES → Observer
│ └─ NO → Do you need undo/redo?
│ ├─ YES → Command
│ └─ NO → Do handlers form a pipeline?
│ ├─ YES → Chain of Responsibility
│ └─ NO → Direct method call
│
└─ NO → Is this about resilience or async work?
├─ Async pipeline → Producer/Consumer
├─ Unreliable service → Circuit Breaker
└─ Complex subsystem → Facade / Adapter
Pattern Combinations
Patterns work well together. Common pairings:
- Factory + Strategy — Factory creates strategy instances by name
- Observer + Command — Commands published as events with undo support
- Facade + Adapter — Facade delegates to adapted third-party APIs
- Decorator + Chain — Each chain handler decorates the processing
- Circuit Breaker + Retry (Decorator) — Retry inside the breaker window
Anti-Patterns to Avoid
Singleton overuse — Use dependency injection instead when possible.
Singletons make testing harder and hide dependencies.Factory for one type — If you only ever create one class, a factory
adds complexity without benefit.Deep decorator stacks — More than 3-4 decorators becomes hard to
debug. Consider a pipeline or middleware approach instead.Observer memory leaks — Always unsubscribe when listeners are
destroyed. Use weak references for long-lived event buses.God Facade — A facade should simplify, not become a dumping ground.
If it grows beyond ~10 methods, split into multiple facades.
When NOT to Use a Pattern
- The code is simple — Don't add patterns preemptively.
- You have one implementation — Strategy/Factory need at least 2 variants.
- Performance is critical — Patterns add indirection. Profile first.
- Your team doesn't know it — Code clarity > clever architecture.
"A pattern is a solution to a problem in a context. No problem, no pattern."
This is 1 of 14 resources in the Python Developer Pro toolkit. Get the complete [Python Design Patterns] with all files, templates, and documentation for $29.
Or grab the entire Python Developer Pro bundle (14 products) for $159 — save 30%.
Top comments (0)