Low Level Design
Design Patterns — The Complete Guide
A practical overview of the 23 Gang of Four design patterns — what they are, how they're grouped, and when to reach for each one.
What are Design Patterns?#
Design patterns are proven, reusable solutions to commonly occurring problems in software design. They are not finished code — they are templates or blueprints that you adapt to your specific situation.
In Low-Level Design (LLD), design patterns provide guidelines for structuring class hierarchies, defining object interactions, and organising code in a way that is:
- Reusable — the same pattern solves similar problems across different contexts
- Maintainable — well-known structure makes code easier to read and modify
- Extensible — patterns align with SOLID principles, especially Open/Closed
Origin — The Gang of Four#
Design patterns were popularised by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides in their 1994 book Design Patterns: Elements of Reusable Object-Oriented Software — commonly called the GoF (Gang of Four) book.
The book catalogued 23 patterns grouped into three categories.
The Three Categories#
Creational Patterns — How objects are created#
These patterns abstract the instantiation process, making a system independent of how its objects are created, composed, and represented.
| Pattern | One-liner |
|---|---|
| Singleton | Ensures a class has exactly one instance |
| Factory Method | Lets subclasses decide which class to instantiate |
| Abstract Factory | Creates families of related objects without specifying concrete classes |
| Builder | Constructs complex objects step by step |
| Prototype | Creates objects by cloning an existing instance |
When to think creational: You find yourself using new in many places, or object construction is getting complex, conditional, or duplicated.
Structural Patterns — How objects are composed#
These patterns deal with object composition, creating relationships between objects to form larger structures.
| Pattern | One-liner |
|---|---|
| Adapter | Makes incompatible interfaces work together |
| Bridge | Decouples abstraction from implementation so both can evolve independently |
| Composite | Treats individual objects and groups of objects uniformly (tree structures) |
| Decorator | Adds responsibilities to objects dynamically without subclassing |
| Facade | Provides a simplified interface to a complex subsystem |
| Flyweight | Shares state to support large numbers of fine-grained objects efficiently |
| Proxy | Provides a surrogate or placeholder to control access to another object |
When to think structural: You're dealing with class explosions from inheritance, legacy system integration, or you need to add behaviour without modifying existing code.
Behavioral Patterns — How objects communicate#
These patterns characterise how classes and objects interact and distribute responsibility.
| Pattern | One-liner |
|---|---|
| Chain of Responsibility | Passes requests along a chain of handlers |
| Command | Encapsulates a request as an object |
| Iterator | Provides a way to sequentially access elements without exposing the underlying representation |
| Mediator | Defines an object that encapsulates how objects interact |
| Memento | Captures and restores an object's internal state |
| Observer | Notifies dependents automatically when an object's state changes |
| State | Lets an object alter its behavior when its internal state changes |
| Strategy | Defines a family of algorithms and makes them interchangeable |
| Template Method | Defines the skeleton of an algorithm, deferring some steps to subclasses |
| Visitor | Lets you add further operations to objects without modifying them |
When to think behavioral: You have complex conditional logic based on state, you need to decouple senders from receivers, or you want to add new operations to existing class hierarchies.
How to Pick the Right Pattern#
Ask yourself:
-
What's the problem?
- Object creation complexity → Creational
- Class/object composition → Structural
- Object interaction/algorithm → Behavioral
-
What relationship are you modelling?
- "I need exactly one" → Singleton
- "I need compatible interfaces" → Adapter
- "I need to add behaviour at runtime" → Decorator
- "I need to change behaviour based on state" → State or Strategy
- "I need to notify many objects of a change" → Observer
-
What SOLID principle is being violated?
- OCP (adding new types breaks existing code) → Factory, Strategy, Command
- SRP (one class doing too much) → Facade, Decorator, Chain of Responsibility
Anti-Patterns to Avoid#
| Anti-Pattern | Better Alternative |
|---|---|
| Using Singleton for everything | Dependency injection |
| Deep inheritance chains | Decorator or Strategy |
| Giant switch/if-else on type | Factory or Strategy |
| Client knowing too much about subsystems | Facade |
| Null checks everywhere | Null Object |
Summary#
Design patterns are a shared vocabulary. When you say "use the Strategy pattern here," every engineer on your team understands the intent, the trade-offs, and the structure — without reading the code. That's their real value.
Start with the problem, not the pattern. Applying a pattern for its own sake adds unnecessary complexity. Reach for patterns when they solve a concrete pain point you can name.
| References | Links |
|---|---|
| Canonical Reference | Refactoring Guru — Design Patterns |
| Original Book | Design Patterns by Gamma, Helm, Johnson, Vlissides (GoF, 1994) |