You know the feeling. A teammate's PR shows up with three new if/elseif branches, and your stomach drops because you've seen this shape before — six months from now, this method is going to be 200 lines, and nobody's going to want to touch it. You can't quite name the move that fixes it, but you know there's a name.
That's what design patterns are for. They're the names we give to solutions that keep showing up. You don't memorize them to look smart — you learn them so the next time the same shape walks in, you recognize it and reach for the move that fits.
This catalog is a tour of the 23 patterns from the original "Gang of Four" book. Each one has its own dedicated page with a real-world scenario, code in five languages, and the patterns it relates to. If you're looking for something specific, jump straight to the family. If you're browsing, read top to bottom — the patterns build on each other.
How the catalog is organized
The 23 patterns split into three families. The split isn't arbitrary — it tells you what kind of problem the pattern is solving:
- Creational — about how objects get created. Reach for these when "I need an X" is harder than it sounds.
- Structural — about how objects compose. Reach for these when you need to put pieces together without rigid coupling.
- Behavioral — about how objects communicate and divide work. Reach for these when responsibility is leaking across boundaries.
Each entry below opens with the intent in one sentence, plus a quick "reach for it when…" hook so you can scan.
Creational patterns
These are about making objects without the calling code knowing too much about which concrete class is being made. The shared question they answer: "how do I keep flexibility about what I create without leaking that decision everywhere?"
- Abstract Factory — Produce families of related objects without tying the caller to specific classes. Reach for it when you swap entire UI kits, database drivers, or platform APIs.
- Builder — Construct complex objects step by step, optionally varying the construction sequence. Reach for it when an object's constructor is taking 8+ parameters and you've started introducing
nulldefaults. - Factory Method — Let subclasses decide which class to instantiate. Reach for it when a base class needs to create something but doesn't know exactly what.
- Prototype — Clone existing objects instead of building them from scratch. Reach for it when object construction is expensive but variations are cheap.
- Singleton — Ensure a class has exactly one instance. Reach for it sparingly — it's the most over-used pattern in the catalog, and 80% of "Singleton" use cases are really "this should be a service in your DI container."
Structural patterns
These are about composition: how do you build bigger things from smaller things without making the relationship rigid? Different patterns answer different versions of "this object needs to look like that" or "I want to put these pieces together without wiring them tightly."
- Adapter — Make an existing class work with a different interface. Reach for it when integrating a third-party library whose API doesn't match what your app expects.
- Bridge — Decouple an abstraction from its implementation so they can vary independently. Reach for it when you have an N×M class explosion (e.g., shapes × renderers).
- Composite — Treat individual objects and groups of objects uniformly. Reach for it when you have a tree of things — files and folders, UI elements, expressions in an interpreter.
- Decorator — Add behavior to an object dynamically without changing its class. Reach for it when you want to layer optional features (compression on a stream, caching on a repository, retry on a client).
- Facade — Provide a simple interface to a complicated subsystem. Reach for it when callers shouldn't need to know about every moving part of a library you wrote.
- Flyweight — Share common state between many objects to save memory. Reach for it rarely — only when you've measured a real memory problem with thousands of similar objects.
- Proxy — Stand in for another object, controlling access to it. Reach for it when you need lazy loading, access control, logging, or remote calls behind the same interface as the real thing.
Behavioral patterns
These are about how objects collaborate. The shared question: "how do I move responsibility around without making the call graph a tangle?" These tend to be the most subtle — the ones that take the most reps to recognize in the wild.
- Chain of Responsibility — Pass a request along a chain of handlers until one handles it. Reach for it for middleware, validation pipelines, logging filters.
- Command — Turn a request into an object so it can be queued, logged, or undone. Reach for it for queues, undo/redo, transactional operations, scheduled jobs.
- Iterator — Walk through a collection without exposing its internals. Reach for it when you're hand-rolling indexed loops over a structure that hides its shape (a tree, a paginated API, a stream).
- Mediator — Centralize complex communications between objects. Reach for it when you have N objects talking to each other and the wiring is starting to look like spaghetti.
- Memento — Capture an object's internal state so it can be restored later. Reach for it for undo, snapshots, time-travel debugging.
- Observer — Notify dependents when an object changes state. Reach for it for event systems, reactive UIs, pub/sub, model→view sync.
- State — Let an object alter its behavior when its internal state changes. Reach for it when you have a
switch (status)block that's growing — order processing, document workflows, connection lifecycle. - Strategy — Define a family of algorithms and make them interchangeable. Reach for it when you have an
if/elseifladder that keeps growing — payments, sorting, pricing, validation. - Template Method — Define the skeleton of an algorithm in a base class and let subclasses fill in steps. Reach for it for export pipelines, test fixtures, document generators.
- Visitor — Add operations to a class hierarchy without modifying it. Reach for it for AST walkers, report generators over polymorphic data, static-analysis tools.
- Interpreter — Define a grammar and an interpreter for sentences in that grammar. Reach for it for DSLs, query languages, simple rule engines — but lean on existing parsers when you can.
Pro Tips
- Don't apply a pattern just because you can. Patterns earn their cost when the same shape keeps showing up. One
ifis a code smell only if it's followed by four more. - Names are half the value. The biggest win of patterns isn't the structure — it's that you can say "this should be Strategy" in a code review and your teammate immediately knows what you mean.
- Patterns travel. The same pattern looks different in PHP, Go, and Python — but the shape of the problem and the solution is identical. Each entry in this catalog shows the same pattern in five languages so you can see what's essential and what's syntax.
- Two patterns often look identical at first glance. Strategy vs. State, Decorator vs. Proxy, Adapter vs. Facade — the difference is intent, not structure. The "Relations with Other Patterns" section on each page is where you go to disambiguate.
Final Tips
The first time I read the original GoF book I didn't get most of it — it felt like reference material with no connection to anything I was building. It only clicked years later when I noticed the same five problems recurring at every job. That's when the names started doing real work for me.
Don't try to learn all 23 in a weekend. Pick the one you've felt most this week and read its page. Next week, do another. Inside a quarter you'll have the vocabulary, and the moment a teammate's PR comes in with the wrong shape, the right name will be on the tip of your tongue.



