Every pattern post in this series showed one pattern on its own: a copy of CornerStore with exactly one smell fixed. That’s great for learning, but it’s not how real code works. In real code, patterns meet. A facade calls a validation chain. A state change notifies observers, which send messages through a bridge.

So the last piece of the repository is the capstone: one copy of CornerStore with all 23 patterns applied, one commit at a time, with the golden master checked after every single one.


Agenda:

  1. The Rules
  2. Where the Patterns Meet
  3. The Whole Flow
  4. The Numbers
  5. What the Capstone Really Teaches
  6. Walk Through It Yourself

The Rules

The capstone followed the same discipline as the rest of the series, just 23 times in a row:

  1. Start from an unchanged copy of the baseline.
  2. Apply one pattern per commit.
  3. After every commit: build with zero warnings, run every test, and check the trading-day transcript still matches the baseline byte for byte.
  4. Finish with zero SMELL markers left in the code.

The order mattered. Singleton went first, because it touches more files than anything else, and doing it later would have meant redoing other work. After that, the patterns were applied area by area: catalogue, pricing, checkout, cart, order lifecycle, back office and reporting.


Where the Patterns Meet

This is the part the individual solutions can’t show you.

The catalogue combines Prototype, Composite, Iterator and Flyweight. Products and bundles share one item interface, variants clone their parent, iterators walk the category tree and imported listings share their specifications.

Pricing combines Abstract Factory, Strategy, Decorator and Interpreter. A regional factory supplies matching tax and surcharge rules, a strategy prices the shipping method, decorators add the optional extras and an expression tree evaluates promo rules. Four patterns, one quote.

Checkout is where it gets interesting. Remember how the Facade post showed the payment switch and the courier XML travelling into the facade, still marked as smells? In the capstone, they finally get fixed in place. The facade now builds a quote, runs the Chain of Responsibility validators, charges through a Factory Method creator, creates the order with a Builder and books the courier through the Adapter. Five patterns, one front door.

The cart pairs Memento and Mediator: snapshots for undo, and a hub that keeps the widgets in sync.

The order lifecycle chains three patterns together. A State object performs a legal transition, the order service notifies its Observers, and the notification observer sends the message through a Bridge to the customer’s email or SMS channel.

The back office combines Proxy and Command. Commands run against the protected inventory interface, the caching proxy stays accurate after every stock change, and the invoker keeps the audit log.

Reporting finishes what Template Method started. That post ended with a duplicated type switch left inside both exporters, waiting for Visitor. In the capstone, the template owns the workflow and a visitor handles each product type. Each exporter is left with one job: its output format.


The Whole Flow

Here’s a checkout from cart to notification, labelled with the pattern that handles each step:

flowchart LR
    Cart["Cart state<br/>Memento"] --> Mediator["CartMediator<br/>Mediator"]
    Mediator --> Facade["CheckoutFacade<br/>Facade"]
    Facade --> Pricing["PricingService<br/>Abstract Factory, Strategy,<br/>Decorator, Interpreter"]
    Pricing --> Validation["OrderValidator<br/>Chain of Responsibility"]
    Validation --> Payment["PaymentProcessorCreator<br/>Factory Method"]
    Payment --> Orders["OrderService and builders<br/>Builder"]
    Orders --> Inventory["Inventory proxies<br/>Proxy"]
    Inventory --> Shipping["ShipFastAdapter<br/>Adapter"]
    Shipping --> State["OrderState<br/>State"]
    State --> Subscribers["OrderService.NotifyObservers<br/>Observer"]
    Subscribers --> Messages["Order messages and IChannel<br/>Bridge"]
    Orders --> Reports["ReportService"]
    Reports --> Exporter["ReportExporter<br/>Template Method"]
    Exporter --> Visitor["ReportTotalsVisitor<br/>Visitor"]

When a single checkout passes through that many patterns, I find it helps to remember that each box started life as a smell in the baseline.


The Numbers

  Baseline Capstone
Source files 55 124
Lines of C# 2,571 3,835
SMELL markers 62 0
Capstone tests n/a 131
Trading-day transcript 417 lines the same 417 lines

More than twice the files and about 50% more code, for the exact same behaviour.

And one small story from the very end. The final check, “zero SMELL markers”, caught a leftover: the Memento commit had removed four S18 markers but missed the one on the Cart class itself. It was removed in the last commit. It’s a tiny thing, but it’s exactly why you write the check down instead of trusting yourself (or an AI agent) to remember.


What the Capstone Really Teaches

Here’s my honest take after building all of this: the capstone is a showcase, not a recommendation.

Look at that table again. The capstone has more than twice the files of the baseline to do exactly the same thing. For a small shop with two regions and three shipping methods, a lot of these patterns are more structure than the problem needs. If CornerStore were a real product, I wouldn’t apply all 23. I’d apply the handful whose problems were actually hurting, and leave the rest until they did.

That’s the same lesson I ended my 2023 post on: design patterns shouldn’t be applied indiscriminately. They buy flexibility with indirection, and indirection has a cost. Remember KISS.

What the capstone does prove:

  • Patterns compose. Twenty-three of them can live in one codebase without fighting, as long as each one has a clear job.
  • Small, verified steps make big refactors safe. Twenty-four commits, each one building, testing and matching the transcript, add up to a complete restructure with zero behaviour change.
  • A golden master is a superpower. None of this would be safe without it.

So use the capstone the way you’d use a reference book: to see how patterns can fit together. Then go back to your own code and apply only what it needs.


Walk Through It Yourself

Build and test the capstone:

dotnet build capstone\Capstone.slnx -c Release
dotnet test capstone\Capstone.slnx -c Release

The best way to explore it is commit by commit. Each one applies exactly one pattern on top of the last:

Step Pattern Commit
0 Copy the baseline c4b770f
1 Singleton d9b1204
2 Prototype 7750e74
3 Composite 015407a
4 Iterator 057f63e
5 Flyweight d69980f
6 Abstract Factory ab7f994
7 Strategy d682f69
8 Decorator 7ffe9bc
9 Interpreter f3e3a6a
10 Factory Method d38ab38
11 Adapter aec0890
12 Builder fab936c
13 Chain of Responsibility 253627b
14 Facade 6203bf9
15 Memento 62bfa4e
16 Mediator 511d631
17 State f6f4f67
18 Observer eb54236
19 Bridge cf4c35f
20 Proxy da5d063
21 Command 0446f38
22 Template Method cead8ef
23 Visitor 81f424a

The capstone README maps every pattern to the files where it lives.

There’s one post left, and it’s a different kind of story: how all of this was built.


Previous: Commonly Confused Patterns · Next: Built with Microsoft HVE Core