Contents

Chapter 1

When to Use Which Pattern — A Decision Guide

Quick Reference

ProblemPatternCategory
Need exactly one global instanceSingletonCreational
Create objects without specifying classFactoryCreational
Complex object constructionBuilderCreational
Incompatible interfaceAdapterStructural
Add behavior without subclassingDecoratorStructural
Simplify complex subsystemFacadeStructural
Notify multiple objects of state changeObserverBehavioral
Swap algorithms at runtimeStrategyBehavioral
Encapsulate actions with undo supportCommandBehavioral
Pass request through handler chainChain of ResponsibilityBehavioral
Coordinate async producers & consumersProducer/ConsumerConcurrency
Protect calls to unreliable servicesCircuit BreakerConcurrency

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

1. Singleton overuse — Use dependency injection instead when possible.

Singletons make testing harder and hide dependencies.

2. Factory for one type — If you only ever create one class, a factory

adds complexity without benefit.

3. Deep decorator stacks — More than 3-4 decorators becomes hard to

debug. Consider a pipeline or middleware approach instead.

4. Observer memory leaks — Always unsubscribe when listeners are

destroyed. Use weak references for long-lived event buses.

5. 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."

Python Design Patterns v1.0.0 — Free Preview