Vasu Patel logoVasu Patel
← Patterns of Good Design
All chapters in this track
  1. 01Chapter 1: Why Patterns Exist — Vocabulary, Not a Checklist
  2. 02Chapter 2: Patterns and SOLID: How They Relate
  3. 03Chapter 3: Creational Patterns I: Factory Method & Abstract Factory
  4. 04Chapter 4: Creational Patterns II: Builder, Singleton, Prototype
  5. 05Chapter 5: Structural Patterns I: Adapter & Facade
  6. 06Chapter 6: Structural Patterns II: Decorator & Proxy
  7. 07Chapter 7: Structural Patterns III: Composite, Bridge & Flyweight
  8. 08Chapter 8: Behavioral Patterns I: Strategy & Template Method
  9. 09Chapter 9: Behavioral Patterns II: Observer & Mediator
  10. 10Chapter 10: Behavioral Patterns III: Command & Memento
  11. 11Chapter 11: Behavioral Patterns IV: State & Chain of Responsibility
  12. 12Chapter 12: Behavioral Patterns V: Iterator & Visitor
  13. 13Chapter 13: Anti-Patterns and Overuse: Recognizing "Pattern Fever"
  14. 14Chapter 14: How Dynamic and Functional Languages Solve These Problems Differently
  15. 15Chapter 15: Architectural Patterns I: MVC/MVVM & Layered/Hexagonal Architecture
  16. 16Chapter 16: Architectural Patterns II: Event-Driven Architecture & CQRS
  17. 17Chapter 17: Architectural Patterns III: The Repository Pattern
  18. 18Chapter 18: Recognizing Which Pattern Fits an Interview Design Prompt

Chapter 2 of 18

Chapter 2: Patterns and SOLID: How They Relate

Why this matters

Patterns and the SOLID principles (covered fully in the companion OOP book) are often taught as separate topics, but almost every classic pattern is best understood as SOLID principles applied to a specific, recurring shape of problem. Seeing this connection explicitly means you don't need to memorize each pattern's rationale independently — you can often derive why a pattern is structured the way it is directly from the principle it satisfies.

The core concept

[IN PRACTICE] Here's the mapping, pattern-category by principle, that recurs throughout this book:

SOLID principleHow patterns embody it
Single ResponsibilityFacade (Ch. 5) separates "orchestrating a subsystem" from the subsystem's own responsibilities; Command (Ch. 10) separates "requesting an action" from "performing it"
Open/ClosedStrategy (Ch. 8), Decorator (Ch. 6), and State (Ch. 11) all let you add new behavior via a new class, without modifying existing, tested code — this is OCP's exact definition, expressed as a pattern
Liskov SubstitutionEvery pattern built on an interface with multiple implementations (Strategy, Observer, State) depends on LSP holding — if an implementation isn't truly substitutable, the pattern breaks in exactly the way Chapter 5 of the OOP book describes
Interface SegregationObserver (Ch. 9) typically splits "subject" and "observer" into narrow, single-purpose interfaces rather than one bloated notification interface
Dependency InversionAbstract Factory (Ch. 3), Strategy (Ch. 8), and the Repository pattern (Ch. 17) all exist specifically to let a high-level module depend on an abstraction instead of a concrete, volatile low-level detail

A worked example: Strategy as OCP made concrete

Before — OCP violated, exactly as in the OOP book's Chapter 9 example:

class ShippingCalculator {
  calculate(method: string, weightKg: number): number {
    if (method === "standard") return weightKg * 2;
    if (method === "express") return weightKg * 5;
    // A new shipping method means editing this method and re-testing every existing branch.
    throw new Error("Unknown method");
  }
}

After — the Strategy pattern, which is this exact fix, formalized and named:

interface ShippingStrategy {
  calculate(weightKg: number): number;
}

class StandardShipping implements ShippingStrategy {
  calculate(weightKg: number): number { return weightKg * 2; }
}
class ExpressShipping implements ShippingStrategy {
  calculate(weightKg: number): number { return weightKg * 5; }
}

class ShippingCalculator {
  calculate(strategy: ShippingStrategy, weightKg: number): number {
    return strategy.calculate(weightKg); // never changes when a new strategy is added
  }
}

If this looks identical to the OOP book's Open/Closed example, that's the point: Strategy is OCP's fix for the "growing conditional" problem, given a name. Once you see this, half of the behavioral patterns in Part 3 of this book will feel like variations on a theme you already understand from SOLID, rather than new things to memorize from scratch.

from typing import Protocol

class ShippingStrategy(Protocol):
    def calculate(self, weight_kg: float) -> float: ...

class StandardShipping:
    def calculate(self, weight_kg: float) -> float:
        return weight_kg * 2

class ShippingCalculator:
    def calculate(self, strategy: ShippingStrategy, weight_kg: float) -> float:
        return strategy.calculate(weight_kg)

Why this connection matters for learning patterns faster

[SENIOR INSIGHT] Once you internalize this mapping, learning a new pattern becomes a matter of asking "which SOLID principle is this satisfying, for which specific recurring shape of problem?" rather than memorizing an unrelated class diagram. This is also why patterns cluster the way they do: most creational patterns (Chapters 3–4) are fundamentally about Dependency Inversion (decoupling what gets created from how it gets constructed); most structural patterns (Chapters 5–7) are about Interface Segregation and Single Responsibility (composing focused pieces rather than bloated ones); most behavioral patterns (Chapters 8–12) are about Open/Closed and Liskov Substitution (adding behavior via new, substitutable classes).

Common mistakes

  1. Treating SOLID and patterns as two separate bodies of knowledge to memorize independently, missing that most patterns are simply SOLID applied to a specific recurring shape — this connection is a genuine shortcut, not just a tidy way to organize a book.
  2. Applying a pattern without checking that the underlying SOLID principle actually needs applying. If there's no real OCP pressure (no evidence a second case is coming — see Chapter 1's discipline and the OOP book's premature-abstraction chapter), introducing Strategy is premature the same way introducing an unjustified interface is.
  3. Forgetting that a pattern's value depends on the principle actually holding. A Strategy implementation that isn't truly substitutable for another (violates LSP) breaks the pattern's entire premise, even though the code might still compile and run.
  4. Assuming every pattern maps to exactly one principle. Most map primarily to one or two, but real patterns often reinforce several at once (Abstract Factory touches both DIP and OCP, for instance) — the table above is a primary association, not an exclusive one.

Checklist: using the SOLID connection while learning patterns

  1. For each new pattern, ask "which SOLID principle does this satisfy, and for what specific recurring problem shape?" before memorizing its structure.
  2. Before applying a pattern, verify the underlying principle actually needs applying — real evidence of a growing conditional (OCP), a hard-wired volatile dependency (DIP), or a bloated interface (ISP) — not a guess.
  3. When a pattern implementation feels awkward, check whether an SOLID principle is being violated underneath it — e.g., an implementation that isn't substitutable (LSP) will make any behavioral pattern built on it fragile.
  4. Use the category-to-principle clustering (creational→DIP, structural→SRP/ISP, behavioral→OCP/LSP) as a mental shortcut when trying to recall which pattern fits a given problem.

Discussion / interview questions

  1. "How does the Strategy pattern relate to the Open/Closed Principle?" Strong answer: Strategy is essentially OCP's fix (replacing a growing conditional with an interface and one implementing class per case) given a name — new behavior is added via a new class, without modifying the class that uses the strategy.

  2. "Which SOLID principle do most creational patterns primarily serve, and why?" Strong answer: Dependency Inversion — creational patterns exist to decouple the code that uses an object from the code that decides how to construct it, which is DIP's core concern applied to object creation specifically.

  3. "Can a pattern be implemented in a way that violates the very SOLID principle it's supposed to embody? Give an example." Strong answer: Yes — e.g., a Strategy implementation that isn't truly substitutable (throws under conditions callers don't expect) violates LSP, which undermines the whole pattern even though the code compiles; or an Abstract Factory that's still hard-wired to one concrete factory internally doesn't actually achieve DIP.

  4. "Why might understanding this SOLID-to-pattern mapping help you learn new, less common patterns faster?" Strong answer: Instead of memorizing a new class diagram from scratch, you can ask what recurring problem and which principle it addresses, and derive much of the pattern's structure from principles you already understand.

Chapter summary / cheat sheet

  • Most classic patterns are SOLID principles applied to a specific, recurring shape of problem — not a separate, unrelated body of knowledge.
  • Strategy, Decorator, and State primarily embody Open/Closed. Abstract Factory, Strategy (again), and Repository primarily embody Dependency Inversion. Facade and Command primarily embody Single Responsibility. Observer often embodies Interface Segregation. Every interface-based pattern depends on Liskov Substitution actually holding.
  • Before applying a pattern, verify the underlying principle has a real, current need — the same discipline Chapter 1 established for pattern vocabulary generally.
  • Use "which principle, for which problem shape" as a faster way to learn and recall new patterns than memorizing class diagrams independently.