Cheat sheet: Design patterns
Every pattern on one page: its memory hook and the points worth saying out loud. Print it (Ctrl/⌘ P) and re-read it before a practice session; open the page behind any card when something doesn't come back to you. Built automatically from the pages, so it always matches them.
Making objects
Factory method
“Same door, different vehicle”
The release steps are fixed; each dock decides what rolls out.
- Avoid
- A factory for a single class
- Returning the concrete class
- Moving the if/elif, not removing it
Abstract factory
“Buy the set, not the pieces”
One kit makes every part, so the parts always match.
- Avoid
- Families that don't need to match
- Adding a part type often
- Passing the city string around anyway
Builder
“Order it, then wrap it”
Name each part as you go; you get the finished thing only at the end, checked.
- Avoid
- A builder for a two-field object
- No validation in build()
- Returning a mutable product
Prototype
“Copy the signed contract”
Start from a finished one, change what differs, and make sure the copy shares nothing.
- Avoid
- Shallow copies of mutable insides
- Handing out the prototype itself
- Copying identity
Singleton, and why to inject instead
“One clock on the wall”
One shared instance everyone reads, and anyone can move.
- Avoid
- A singleton as a global variable
- Mutable state in the singleton
- Unsafe lazy creation
Fitting objects together
Adapter
“A travel plug”
Same hairdryer, foreign socket: a small piece in between that only translates.
- Avoid
- Business logic in the adapter
- Leaking the adaptee's types
- Swallowing errors
Decorator
“Parcel in layers”
Each wrapper adds one protection; from outside it's still the same parcel.
- Avoid
- Forgetting to forward a method
- Order chosen by accident
- Decorators that depend on each other
Facade
“Ask reception”
One counter in front of many departments, and it knows the order.
- Avoid
- A facade for everything
- Business rules hidden in the facade
- Forbidding direct access
Proxy
“The agent answers first”
Same phone number, but the agent decides whether the real person is disturbed.
- Avoid
- Hiding that answers may be stale
- A remote proxy pretending the network isn't there
- Proxy and real object drifting apart
Composite
“Ask down the org chart”
Everyone answers the same question: count yourself, or ask your reports and add up.
- Avoid
- Child methods on leaves
- Type checks creeping back
- Recomputing big totals on every call
Bridge
“Any remote, any TV”
What to say and how to send it vary separately, joined by one agreed interface.
- Avoid
- An implementor interface shaped by one side
- Channels that know alert kinds
- Bridging a single dimension
Flyweight
“One map on the wall”
Share what's the same for everyone; let each one carry what's theirs.
- Avoid
- Putting changing state in the flyweight
- Mutable flyweights
- Bypassing the factory
Choosing behaviour
Strategy
“Same trip, choose the route”
One journey; the routing rule is a swappable part.
- Avoid
- A strategy that knows the context
- Choosing the strategy inside the context
- Classes where functions would do
State
“The light knows what's next”
Each state knows its own rules and its successor; the object just asks the current one.
- Avoid
- States that set the context's fields directly
- Forgetting the default refusal
- Transitions hidden in the context
Template method
“The order of service is fixed”
The base class owns the running order; subclasses fill in their own parts.
- Avoid
- Letting subclasses override the template method
- Hooks for everything
- Subclasses calling back up in surprising ways
Command
“Write it on a ticket”
A request becomes an object: it can wait, be read back, crossed out, or kept as a record.
- Avoid
- Undo that doesn't match run
- Recording refused commands in history
- Commands that hold live objects for later
Chain of responsibility
“Airport checkpoints”
Each stop checks one thing and stops you or waves you on; routes can add stops.
- Avoid
- A chain with no safe end
- Handlers that depend on order silently
- Expensive checks first
Objects talking
Observer
“Publish, don't phone”
The subject announces; whoever subscribed reacts. It never needs to know who they are.
- Avoid
- Observers that depend on each other's order
- One failure stops the rest
- Slow work in the subject's call
Mediator
“Talk to the tower”
Planes don't negotiate with each other; each reports to the tower, which tells the others.
- Avoid
- The god mediator
- Colleagues still calling each other
- Business data inside the mediator
Iterator
“Next one, please”
Ask for the next element; the collection fetches it however it likes.
- Avoid
- Reusing a spent iterator
- Changing the collection while looping
- Hiding expensive work
Visitor
“The inspector brings the checklist”
Each flat opens the door and says what it is; the visiting inspector applies the right checks.
- Avoid
- Using visitor when types change often
- A default visit method that does nothing
- Visitors that change the elements
Memento
“A save point”
Press save, get a slot you can't read; load it later and everything's back.
- Avoid
- Snapshots that share mutable data
- Caretakers that read snapshots
- Unbounded history
Interpreter
“A recipe card”
A tiny language of a few instruction kinds; any card is a tree you can follow.
- Avoid
- Letting the language grow without a plan
- Using eval() on user text
- Unclear errors
Beyond the book
Dependency injection
“The chef doesn't grow the vegetables”
A class cooks with what it's handed; one place decides what gets delivered.
- Avoid
- Injecting a service locator
- Constructors with ten parameters
- Wiring scattered everywhere
Repository and unit of work
“Pay for the whole basket”
Collect the changes; commit them together or put everything back.
- Avoid
- One repository per table instead of per aggregate
- Repositories that commit on their own
- Leaking queries into business code
Choosing a pattern
“Diagnose, then prescribe”
Start from the symptom in the code, not from the pattern catalogue; sometimes the answer is nothing.
- Avoid
- Pattern first, problem second
- Choosing by the name in the code
- Abstracting before the second case