Design Patterns Wrap-Up: 23 Patterns, 5 Lessons
Wrap-up of Design Patterns A → Z in C# / .NET 10: the five lessons that survive, what to read next, and where each pattern shrinks in modern code.
Table of contents
- Lesson 1 — are patterns vocabulary or solutions?
- Lesson 2 — what shrunk and what survived?
- Lesson 3 — is the cost of every pattern real?
- Lesson 4 — how many patterns does the framework already give you?
- Lesson 5 — how do patterns combine into an architecture?
- What should you read next?
- What should you do tomorrow?
- What if my problem doesn't fit any pattern?
- Where should you go from here?
You started the series wondering why anyone still talks about design patterns thirty years after the Gang of Four book. You finished it, hopefully, with a different question: which pattern am I about to write here?. That shift is the entire payoff. The final article is short by design — a wrap-up, five lessons, and a list of what to read after this. The series stays, the conversation about your codebase begins.
Lesson 1 — are patterns vocabulary or solutions?
The Gang of Four did not invent the patterns. They named them. The eight pattern names every senior C# engineer carries — Singleton, Factory Method, Adapter, Decorator, Strategy, Observer, Iterator, Command — are five-second abbreviations for design choices that used to take a meeting to discuss. The vocabulary itself is the productivity gain.
The corollary is sharp. Using a pattern in code without naming it in a comment is a missed opportunity. The reviewer should not have to deduce that you wrote a Decorator; the class name should say so.
Lesson 2 — what shrunk and what survived?
Every pattern in this series has a 1994 implementation and a
2026 implementation. The 1994 version is class diagrams; the
2026 version is one or two Program.cs lines. The full
inventory lives in the decision-tree
chapter — the short version
fits on a card:
- Records absorbed Builder, Prototype, Memento.
- DI absorbed Singleton, Factory Method, Abstract Factory, Strategy.
yieldabsorbed Iterator.- Pattern matching absorbed Visitor.
event,IObservable<T>, andChannel<T>absorbed Observer.- MediatR absorbed Mediator + Command.
- Middleware absorbed Chain of Responsibility.
- Frameworks absorbed Template Method (
BackgroundService,ControllerBase).
The pattern shape survived because the underlying intent did — "share one instance per process", "swap an algorithm at runtime", "walk a structure". The shape changes with the language; the intent does not.
Lesson 3 — is the cost of every pattern real?
The series said it once per chapter and it bears repeating. Every pattern adds files, indirection, and a name a future reader has to learn. The pattern earns its existence only when the cost pays back — when adding a feature without modifying existing code, when isolating a unit test, when removing real duplication. Three signs you are paying without earning:
- A
Strategywith one implementation. - A
Decoratorthat adds nothing. - A
Facadethat delegates one method to one collaborator.
Delete first; promote later. The rule of three from the Introduction is the discipline that prevents premature abstraction.
Lesson 4 — how many patterns does the framework already give you?
ASP.NET Core's middleware is Chain of Responsibility. EF Core's
proxies are Proxy. IEnumerable<T> is Iterator. record is
Prototype + Memento. Lazy<T> is Singleton. IComparer<T> is
Strategy. BackgroundService is Template Method.
You learned the patterns to read your application code. The
biggest payoff is reading the framework code: the moment you
recognise that app.Use((ctx, next) => ...) is the same shape
as a custom validation pipeline, the framework stops being
magic. The chapters cross-reference these connections at every
turn.
Lesson 5 — how do patterns combine into an architecture?
Each chapter compared one pattern to two or three siblings. The deeper truth is that every real codebase composes patterns. The checkout flow we used as the running example combines:
- Singleton for the
PriceCatalog. - Factory Method for the
IPaymentProcessorchosen by method. - Decorator for logging, retry, and fraud check around the processor.
- Facade for the
CheckoutService. - Mediator for the
OrderPaidnotifications. - Command for the
AddToCart,Checkoutrequests. - State for the order's lifecycle.
- Strategy for discount rules.
- Composite for the cart with bundles.
- Observer for the badge refreshing on cart change.
- Iterator for everything you walk.
Eleven patterns in one feature. None of them is the answer on its own; together they are the architecture. Knowing the names lets you describe that architecture in one paragraph instead of five files of source code. The shape:
flowchart LR
Ctrl[CheckoutController] --> Facade[CheckoutService<br>Facade]
Facade --> Cart[Cart<br>Composite]
Facade --> Pay[IPaymentProcessor<br>Factory Method]
Pay --> Dec[Logging+Retry+FraudCheck<br>Decorator]
Facade --> State[Order<br>State machine]
Facade --> Mediator[IMediator<br>Mediator]
Mediator --> H1[ReserveInventory]
Mediator --> H2[SendEmail]
Mediator --> H3[Analytics]
State --> Strat[IDiscountStrategy<br>Strategy]
Cart --> Cat[PriceCatalog<br>Singleton]
And in C#, the registration that wires those eleven patterns together is small:
// Eleven patterns, one composition root
builder.Services.AddSingleton<IPriceCatalog, PriceCatalog>(); // Singleton
builder.Services.AddKeyedScoped<IPaymentProcessor, StripeProcessor>("stripe"); // Factory Method
builder.Services.Decorate<IPaymentProcessor, FraudCheckPaymentProcessor>(); // Decorator
builder.Services.Decorate<IPaymentProcessor, RetryingPaymentProcessor>();
builder.Services.Decorate<IPaymentProcessor, LoggingPaymentProcessor>();
builder.Services.AddScoped<ICheckoutService, CheckoutService>(); // Facade
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<Program>()); // Mediator + Command
builder.Services.AddKeyedSingleton<IDiscountStrategy, TieredDiscount>("tiered"); // Strategy
// State (Order entity) and Composite (Cart tree) are shape, not registration
What should you read next?
The 1994 GoF book is still worth reading once — for the vocabulary, not for the C++ examples. After that:
- Robert C. Martin, Clean Architecture — connects pattern-level thinking to module boundaries and dependency rules.
- Martin Fowler, Patterns of Enterprise Application Architecture — patterns above the GoF level: Repository, Unit of Work, Service Layer, Domain Model.
- Martin Fowler, Refactoring — how to get to the patterns from real production code.
- Microsoft Learn, Service lifetimes
— the canonical reference for
AddSingleton/AddScoped/AddTransient, which is half the modern .NET pattern story. - refactoring.guru — the cleanest visual explanations of every GoF pattern; great for refreshing one chapter at a time.
- Source code of ASP.NET Core, EF Core, and Roslyn — these are the production-scale demonstrations of the patterns. Read any one for an afternoon and you will see the shapes you learnt here.
What should you do tomorrow?
Five small habits that turn the series into permanent skill:
- Name your classes after the pattern when it fits.
PaymentProcessorAdapter,LoggingPaymentProcessor,OrderStateMachine. Names are half the value. - Add a one-line comment when a pattern is non-obvious.
// Decorator: adds idempotency around the inner processor. - Review PRs through pattern names. "This wants to be a State, not a Strategy." Even if you do not push the change, the conversation tightens.
- When you write
if (type is X), pause. It is often a Strategy or a Visitor in disguise. Sometimes theifis right; sometimes it is the third occurrence and the pattern has just earned its existence. - Re-read one chapter a week for six weeks. The series is long; recognition matters more than recall. Spaced rereading beats one heroic pass.
What if my problem doesn't fit any pattern?
You will, occasionally, design something that does not fit any of the 23 patterns. That is fine. The patterns are common shapes, not the only shapes. When your problem is genuinely new, the right move is to describe it well — give it a name, write the comparison to the patterns it is not, document the intent. That is how new patterns enter the vocabulary in the first place.
The patterns survived 30 years because programmers kept finding the same problems and gave them shared names. The lesson of the series is that you have just joined that conversation. The next person who reads your code — likely you in six months — will thank you for the vocabulary.
Where should you go from here?
- Decision tree: How to choose the right design pattern.
- Series start: Introduction.
- Group entry points: Singleton (Creational), Adapter (Structural), Chain of Responsibility (Behavioral).
Thank you for reading the series. Now go open one of those production codebases I mentioned and find a pattern you recognise. The vocabulary is yours to keep.
Frequently asked questions
What should I read after this series?
Are there design patterns the GoF book missed?
IAsyncEnumerable, Channel<T>, async streams — are arguably the equivalent of new GoF chapters. The 1994 list is the foundation; the conversation has continued.How do I keep getting better at design patterns after the series?
What is the single biggest takeaway from learning all 23 patterns?
if/else ladder you wrote yesterday becomes 'a Strategy waiting to happen'. The same switch over types becomes 'a State machine' or 'a Visitor'. Naming is half the work. The other half is knowing when not to apply a pattern — measured by whether the code is shorter, simpler, and easier to change. If it is not, the pattern was wrong.