Pattern Integration Lab
Build one real feature that legitimately uses several patterns together. The goal is not "use three patterns." The goal is to put yourself in a situation where each pattern has a pressure, and practice seeing the pressure before naming the pattern.
Retrieval Prompts
Answer closed-book before starting:
- What pressure does Strategy absorb? What does Decorator absorb? What does Factory absorb?
- How do you tell whether a pattern is carrying its weight or is pattern salad?
- What are the four rules of simple design, in order?
The Target Feature
Build a PricingEngine for an imaginary online shop. Requirements:
- Three credible pricing algorithms today (regular, seasonal, loyalty).
- Every pricing call must be logged; some deployments also cache results for the same cart for 30 seconds.
- Storefront configuration picks the base strategy; the caller should not know which storefront is which.
- Tests cover: correctness of each strategy, logging happens exactly once per call, caching returns the cached value on a repeat call.
Your language is your choice. Python or TypeScript recommended for brevity.
Workflow
- Name the pressures. In your README, write a table with columns: pressure, smell or force it would produce without a pattern, proposed pattern, cost accepted.
- Write the simplest version first. Three strategies, one
price()call, no decorators. Commit. - Add the decorators. Logging decorator, then caching decorator. Commit each as a separate step.
- Introduce the factory. A
PricingFactorythat assembles strategy + decorators based on storefront config. Commit. - Write the tests. Each algorithm, each decorator, and one end-to-end test through the factory.
- Write an ADR. "ADR 0001: Use Strategy + Decorator + Factory in the PricingEngine." Include alternatives considered (inheritance hierarchy, if/else chain).
Compare and Distinguish
- Strategy vs. Template Method -- which is right here, and why?
- Decorator vs. baking logging into each Strategy -- which is cheaper if you add a fourth strategy later?
- Factory vs. direct construction -- what pressure justifies the factory in this specific feature?
Common Mistake Check
Identify the error in each:
- "I added a
DiscountStrategyinterface even though there is only one discount type today, because you might add more later." - "Logging is hand-written in each of the three strategies; the code is identical, but it's faster to copy."
- "The factory does a
switchon storefront insidePricingEngine.price()instead of in a dedicated class." - "The caching decorator has its own copy of
compute_totalrather than delegating to the inner strategy."
Evidence Check
This lab is complete only if:
- The README has the pressure table described above.
- Each pattern is introduced in a separate commit, and each commit passes tests.
- Tests exist at unit level for each pattern.
- An ADR exists documenting the decision.
- You can explain, in one sentence per pattern, which pressure it is absorbing and what it costs.