Last quarter the discount rule was one if. This quarter it is a forty-line type-code forest: percent off, flat off, buy-one-get-one, a loyalty multiplier, and a branch that only exists for Black Friday. The next promotion will edit the same method again. The tests for the old promotions will run for a change that has nothing to do with them.
That is the kind of pain a design pattern is for. Not “the book listed twenty-three names,” and not a code-review checklist.
A design pattern is a named way to arrange types so a specific change stays local. Principles such as SOLID say why a seam should exist. Patterns say how this one usually looks once you have already felt the pain.
This post is the series glossary and index: the three families, the shared lab the later posts reuse, when a pattern is ceremony, and a living catalog of every post in this section. Later posts link back here instead of re-lecturing Gang of Four.
How to use this page
You do not need to read twenty-three posts in book order.
- Jump by family — creational, structural, or behavioral — if you already know the name and want the pain it targets.
- Follow Start here if you want the patterns that show up in real code (and interviews) first.
- Treat (upcoming) titles as the map, not a 404. Published titles are links. Titles marked (upcoming) are not live yet — do not invent a URL. This page is updated when one ships.
Each pattern post stands alone for its own title. Definitions of the families, the lab domain, and the cargo-cult failure modes live here.
Principles first, then a named shape
If you have just finished the SOLID series, the relationship is:
| SOLID asks | A pattern answers |
|---|---|
| Can I add behavior without editing the core? | Strategy, Decorator, Factory Method |
| Can a subtype keep the caller’s contract? | Adapter (honest wrap) vs a lying subclass |
| Can I test policy without I/O? | Strategy, Proxy, Command as seams you can fake |
Who owns new? | Factory Method, Abstract Factory, Builder — at the edge |
Do not reach for a pattern to “do SOLID.” Reach for one when a change you can name is expensive, and the named arrangement matches that change. The SOLID hub stays the glossary for the five letters; this page stays the map for the named solutions.
Note: MVC, Repository, DAO, and “dependency injection as a pattern” are not in this catalog. They are architectural or framework conventions. Dependency Inversion already has a post in the SOLID series: Depend on Abstractions, Not on new.
The three families, one sentence each
The Gang of Four grouped twenty-three patterns by what they vary. That grouping is still the cheapest way to navigate.
Creational — who is allowed to say new
Creational patterns move object construction out of the code that uses the object, so the user is not welded to a concrete type.
The smell is a policy class that names Stripe, Razorpay, and a test double in the same method, or a constructor with twelve parameters that nobody can call correctly twice.
Structural — how types sit next to each other
Structural patterns compose or wrap types so you can add, hide, or translate a surface without rewriting the thing being wrapped.
The smell is a subclass explosion (“AuditedRetryingCachedGateway”), a vendor SDK leaking into every caller, or a facade that is really just a bag of unrelated methods.
Behavioral — who does the work, and when
Behavioral patterns assign responsibility for an algorithm, a reaction, or a conversation so the participants can change independently.
The smell is a growing switch on a type code, a publisher that knows every listener by name, or an undo feature implemented as a pile of boolean flags.
The lab domain: order, payment, discount
Most posts in this series reuse the same tiny checkout domain as the SOLID series, so you are not re-learning a scenario. Four names, used consistently:
| Type | Role |
|---|---|
Order | The data: id, customer email, line items, total |
PaymentGateway | Charges an order through some provider |
DiscountPolicy | Turns an order total into the amount payable |
OrderProcessor | The policy that coordinates the above |
Order stays a plain data carrier:
public record Order(String id, String customerEmail, List<LineItem> items, BigDecimal total) {}
public record LineItem(String sku, int quantity, BigDecimal unitPrice) {}
If records are new to you, Java Records: Immutable Data Without the Boilerplate covers the shape. The SOLID god-service starting point is in SOLID Roadmap — this series assumes that method has already been split, and asks a different question: once the seams exist, which named arrangement fits the next variant?
A few patterns need a second tiny example because checkout does not naturally grow a tree, a million identical objects, or a grammar. Those are called out in the catalog: Composite, Flyweight, and Interpreter. Everything else should be readable against Order / PaymentGateway / DiscountPolicy.
When patterns are cargo-cult
Patterns go wrong more often from premature naming than from ignorance. The tell is the same one as SOLID: indirection with no second implementation and no second reason to change.
Concrete anti-patterns to refuse:
- A Strategy with one implementer.
PercentDiscountbehindDiscountPolicy, forever alone, plus a config key to select the only option. That is two files to open instead of one. - Singleton as a global bag. A
AppContext.getInstance()that holds the database, the clock, and the current user. You have not limited instances; you have hidden every dependency. - Visitor on a closed set you own. If the types are a sealed hierarchy and the operations are few, an exhaustive
switchis honest. Visitor pays off when operations keep arriving and the element set does not. - Abstract Factory for one family. Three factory classes to produce one gateway, one notifier, and one repository that never vary together.
- Decorator wrapping nothing extra.
LoggingGatewaythat logs a line and forwards, with no second wrapper and no plan for a third. A method call at the call site was enough. - Command objects for a method you run once.
ProcessOrderCommandthat is constructed andexecute()d in the same line as the oldprocessor.process(order)call.
The healthy trigger is a variant you can point at in the git log. Two discount rules, a second payment SDK, a queue that needs undo, a third notification channel. Name the change. If you cannot, do not name a pattern either.
Note: Library and framework code plays by different rules. A published API often needs a stable seam before the second caller exists, because the callers are outside your repository. Application code can wait for evidence.
The catalog
Published titles are links. Titles marked (upcoming) are not live yet — they will become links as those articles ship. Jump to the family that matches the pain; do not treat the book order as a reading order.
Creational
| Pattern | Pain it targets | Post |
|---|---|---|
| Factory Method | Callers should not name the concrete type they receive | Factory Method: Let Subclasses Decide Which Object to Build |
| Abstract Factory | A family of related objects must vary together | Abstract Factory: Families of Objects Without Naming the Concrete Types |
| Builder | Construction has many optional steps and a telescoping constructor | Builder: Assemble Complex Objects Step by Step |
| Prototype | Copying a configured object is cheaper than rebuilding it | Prototype: Copy an Object Instead of Reconstructing It |
| Singleton | Exactly one instance must exist — and you can name why | Singleton: One Instance, Used Carefully |
Structural
| Pattern | Pain it targets | Post |
|---|---|---|
| Adapter | An existing client cannot speak a vendor’s types | Adapter: Make Incompatible Types Talk |
| Bridge | An abstraction and its implementations need to vary independently | Bridge: Split Abstraction from Implementation |
| Composite | A tree of parts should be usable as one part | Composite: Treat Trees of Objects as One |
| Decorator | Behavior should wrap an object without a subclass per combination | Decorator: Add Behavior Without Subclassing the Core |
| Facade | Callers are drowning in a subsystem’s types | Facade: One Simple Front for a Messy Subsystem |
| Flyweight | Many similar objects share a large immutable payload | Flyweight: Share What Does Not Change |
| Proxy | You need a stand-in (lazy, remote, access control) for a real object | Proxy: Stand In for an Object You Cannot Touch Directly |
Composite, Flyweight, and Interpreter use a second tiny example on their own posts; the pain column still tells you when to open them.
Behavioral
| Pattern | Pain it targets | Post |
|---|---|---|
| Chain of Responsibility | Several handlers might own a request; none should hard-code the next | Chain of Responsibility: Pass a Request Until Someone Handles It |
| Command | A request must be queued, logged, or undone as an object | Command: Turn a Request into an Object |
| Interpreter | A small language needs evaluating | Interpreter: Represent a Grammar and Evaluate It |
| Iterator | Callers must walk a collection without seeing its structure | Iterator: Walk a Collection Without Exposing Its Guts |
| Mediator | Colleagues know too many of each other’s names | Mediator: Keep Colleagues from Talking to Each Other |
| Memento | You need a snapshot without exposing private fields | Memento: Snapshot State Without Breaking Encapsulation |
| Observer | Many dependents must react when one object changes | Observer: Notify Dependents When Something Changes |
| State | Behavior should change when internal state changes | State: Change Behavior When Internal State Changes |
| Strategy | An algorithm should be swappable without editing callers | Strategy Pattern: Swap Algorithms Without Editing Callers |
| Template Method | The skeleton of an algorithm is stable; a few steps vary | Template Method: Freeze the Skeleton, Vary the Steps |
| Visitor | New operations keep arriving; the element types do not | Visitor: Add Operations Without Changing the Elements |
Start here
Book order is a catalog, not a curriculum. If you are picking a first path through this section, use interview-and-production frequency, not chapter numbers. Linked titles are live; (upcoming) titles are not.
- Strategy — swap an algorithm
- Factory Method: Let Subclasses Decide Which Object to Build
- Observer: Notify Dependents When Something Changes
- Decorator: Add Behavior Without Subclassing the Core
- Adapter: Make Incompatible Types Talk
- Builder: Assemble Complex Objects Step by Step
- Singleton: One Instance, Used Carefully
- Template Method: Freeze the Skeleton, Vary the Steps
- Facade: One Simple Front for a Messy Subsystem
- Command: Turn a Request into an Object
Wave 2:
- Proxy: Stand In for an Object You Cannot Touch Directly
- Composite: Treat Trees of Objects as One
- State: Change Behavior When Internal State Changes
- Chain of Responsibility: Pass a Request Until Someone Handles It
- Abstract Factory: Families of Objects Without Naming the Concrete Types
- Iterator: Walk a Collection Without Exposing Its Guts
Wave 3 (easy to over-apply):
- Bridge: Split Abstraction from Implementation
- Flyweight: Share What Does Not Change
- Mediator: Keep Colleagues from Talking to Each Other
- Memento: Snapshot State Without Breaking Encapsulation
- Prototype: Copy an Object Instead of Reconstructing It
- Visitor: Add Operations Without Changing the Elements
- Interpreter: Represent a Grammar and Evaluate It
Read the post that matches the pain you have today. Come back here for the family and the “when to skip it” test.
Cheat sheet
Creational who says `new` -> Factory Method, Abstract Factory, Builder, Prototype, Singleton
Structural how types sit together -> Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy
Behavioral who does the work, and when -> Strategy, Observer, Command, Template Method, State, ...
Trigger to apply: a named variant already exists (or is on the ticket)
Trigger to stop: one implementation, no pending second
Not in this map: MVC, Repository, DAO, DI-the-framework
Scoreboard: files touched per new variant, tests that should not have broken
Do:
- Start from the change request, then name the pattern that makes that change an addition.
- Keep data types dumb (records) and put the varying algorithm behind one small interface.
- Let construction live at the edge —
main, a config class, or your DI container. - Link back here from later posts rather than re-defining the three families.
Don’t:
- Introduce a pattern for a variation your product does not have.
- Treat the twenty-three names as a code-review rubric.
- Confuse a pattern with a principle: Strategy is one shape that serves Open-Closed; it is not a requirement of Open-Closed.
- Add MVC, Repository, or a DI framework to this list and call it Gang of Four.
Wrap-up
Design patterns are a vocabulary for arrangements you have already earned. Creational patterns keep new out of policy. Structural patterns wrap, hide, or compose types. Behavioral patterns move an algorithm, a reaction, or a conversation so the next variant does not edit every participant.
The catalog on this page is the map of the section. Every Gang of Four name has a post; start with the algorithm that is already growing an if forest — that is Strategy, and it is the cheapest first step in this series.