This is the whole ladder on one card. Each row is a pattern you met in Part II, compressed to the three things you need at a glance: the problem it answers, the shape it takes in code or config, and the honest signal to skip it. The skip-if column is the one most reference cards omit and the one a small team reads first. Every pattern you adopt is one you maintain forever, so read down the skip-if column before you reach for anything.
The attributions stay in the per-altitude chapters and in Appendix C. The chapters carry the worked snippets; this card carries the shape in a phrase. When two disagree, trust the chapter.
The code-level vocabulary, mostly from the Gang of Four, with a value object (Money) and a null object reaching just past the catalogue. These organise behaviour inside a single boundary. The shapes are plain C#, no library required.
| Pattern | What it solves | The shape | Skip-if |
|---|---|---|---|
| Strategy | Swap an algorithm or behaviour at runtime | An interface with interchangeable implementations, chosen by the caller (CourierMatchingStrategy: nearest, fastest, cheapest) | Only one implementation will ever exist |
| Adapter | Make an incompatible interface fit yours | A wrapper that translates a third-party SDK to your own seam (the payment provider) | You control both sides of the interface |
| Decorator | Add behaviour without subclassing | A wrapper implementing the same interface, layering surge, promo or loyalty on a base price | DI interception already does it |
| Command | Encapsulate an action as an object | A request as data you can queue, retry, undo or audit (place, cancel, add-to-cart) | A direct method call is all you need |
| State | Make behaviour follow an explicit lifecycle | A state object per status, each owning its allowed transitions (the Order lifecycle, placed through delivered) | Two states, one transition: use a bool |
| Proxy | Control access to the real object | A stand-in for lazy loading, access control, caching or a remote call (the lazy-loaded menu image) | No access, laziness or remoting concern |
| Composite | Treat a tree and its parts through one interface | A recursive structure where a node and a leaf share a type (the menu tree: sections, items, modifier groups) | The data is flat, never nested |
| Money | Carry an amount and its currency as one value | An immutable value type owning cents, currency, and the one rounding rule; adding different currencies throws | A genuinely single-currency app that rounds in one place |
| Null Object | Kill scattered null checks for an optional collaborator | A do-nothing implementation of the interface (a silent NullNotifier), selected like any other | Absence that means something the caller must handle |
Honorable mentions: Factory Method (DI absorbs most creation), Facade, Template Method, Chain of Responsibility.
How a single service stays testable and changeable. Dependency Injection is the spine; the rest keep the domain core away from I/O.
| Pattern | What it solves | The shape | Skip-if |
|---|---|---|---|
| Dependency Injection | Inject collaborators instead of newing them up | Constructor parameters resolved by MS.Ext.DI with explicit lifetimes | A one-file script |
| Data Gateway (+ stored procs) | Own a table's SQL in one thin object, no ORM magic | A focused class calling Dapper over stored procedures behind an interface | A genuine throwaway prototype |
| Ports & Adapters (Hexagonal) | Insulate the domain core from I/O | Domain logic depending on interfaces; adapters at the edge wire the DB and network | Tiny CRUD: plain layering is cheaper |
| Pipeline / Middleware | Compose cross-cutting concerns per request | An ordered chain handling auth, logging and validation before the handler | No cross-cutting concerns yet |
| Mediator (command/query split) | Decouple a request from its handler | One handler per use-case, dispatched through a mediator; thin controllers | A three-endpoint service |
| Anti-Corruption Layer | Keep a messy external model out of yours | A translation boundary that maps a third party's model to your domain | No external system, or one you fully control |
| Domain Events | Decouple in-process side effects from the core | An event raised on a change; handlers react (email, audit, projection) | One straightforward side effect: just call it |
| Specification | Reuse one business rule across query, validation and UI | A rule object with IsSatisfiedBy; And/Or/Not compose as a Composite ("open and in range") | The rule only ever runs as one SQL query: write the predicate |
Honorable mentions: Result/ErrorOr error handling, plain Layered architecture. (Worked over-engineering example for this altitude: heavy ORM / EF.)
Download the full PDF for free?
Free download — no account required