Overview Beginner 6 min read

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
  1. Lesson 1 — are patterns vocabulary or solutions?
  2. Lesson 2 — what shrunk and what survived?
  3. Lesson 3 — is the cost of every pattern real?
  4. Lesson 4 — how many patterns does the framework already give you?
  5. Lesson 5 — how do patterns combine into an architecture?
  6. What should you read next?
  7. What should you do tomorrow?
  8. What if my problem doesn't fit any pattern?
  9. 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:

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:

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:

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

The 1994 GoF book is still worth reading once — for the vocabulary, not for the C++ examples. After that:

What should you do tomorrow?

Five small habits that turn the series into permanent skill:

  1. Name your classes after the pattern when it fits. PaymentProcessorAdapter, LoggingPaymentProcessor, OrderStateMachine. Names are half the value.
  2. Add a one-line comment when a pattern is non-obvious. // Decorator: adds idempotency around the inner processor.
  3. 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.
  4. When you write if (type is X), pause. It is often a Strategy or a Visitor in disguise. Sometimes the if is right; sometimes it is the third occurrence and the pattern has just earned its existence.
  5. 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?

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?
Three books and one site. Robert C. Martin's Clean Architecture connects pattern-level thinking to module boundaries. Martin Fowler's Patterns of Enterprise Application Architecture covers the patterns above the GoF level — Repository, Unit of Work, CQRS. Refactoring by Fowler shows how to get to the patterns from real code. Online, refactoring.guru has the cleanest visual explanations of every GoF pattern.
Are there design patterns the GoF book missed?
Several that are now widely used: Repository, Unit of Work (Fowler), CQRS, Saga, Outbox (event-driven). The async-first patterns of modern .NET — 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?
Read other people's code with pattern names in mind. Every PR you review, ask: which pattern is this? Which would have been better? Reading mature codebases (ASP.NET Core source, EF Core source, Roslyn) is the fastest way to see GoF patterns at production scale. Then write your own — small, deliberate, named.
What is the single biggest takeaway from learning all 23 patterns?
Patterns are not solutions; they are names for solutions. The same 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.