Comparison of Patterns
A decision-oriented guide to all 23 GoF design patterns. Covers when to reach for each pattern, how they compare, and how to choose without memorizing isolated definitions.
Introduction: The Real Question: Which Pattern Fits?
Knowing the names of 23 patterns is less useful than recognizing the design pressure behind a problem. A notification system, for example, may need Observer, Mediator, or neither, depending on whether it broadcasts events or coordinates behavior.
This article is a map for that decision. Use the problem's changing dimensions, communication shape, and lifecycle needs to navigate from context to a possible pattern, then compare the trade-offs before committing.
TL;DR / mental model
Choose the pressure, not the pattern name
Start with the force that is making the design uncomfortable: object creation, incompatible interfaces, a growing tree, swappable algorithms, hidden dependencies, or tangled communication. Pick the smallest abstraction that addresses that force; if ordinary composition or a direct method is enough, do not add a pattern.
The Problem It Solves
A pattern catalog is difficult to use when several patterns appear to solve the same surface problem. The comparison gives each choice a context: what is changing, where the decision belongs, what behavior must be composed, and which costs the design is willing to accept.
Participants in the decision
- Design pressure: the variation, coupling, or communication problem that needs attention.
- Pattern candidate: an abstraction that addresses that pressure.
- Closest alternative: another pattern or a simpler design that could also work under different constraints.
- Constraints: lifecycle, performance, ownership, and change frequency that determine whether the extra abstraction is worthwhile.
Pattern Families at a Glance
Before diving into comparisons, here's the full landscape. Each pattern belongs to one of three families, and each family answers a different question.
| Family | Question it answers | Patterns |
|---|---|---|
| Creational | How do I create objects without hardcoding concrete classes? | Factory Method, Abstract Factory, Builder, Singleton, Prototype |
| Structural | How do I compose objects into larger structures while keeping them flexible? | Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy |
| Behavioral | How do I distribute responsibilities and communication between objects? | Chain of Responsibility, Command, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
Decision inputs
Before choosing a name, ask:
- What is changing? Object creation, an interface, a hierarchy, an algorithm, or communication topology?
- Who should make the decision? The caller, the object itself, a subclass, or a central coordinator?
- What lifecycle is needed? Immediate execution, composition, caching, delayed work, undo, or notification?
Use the family as a first filter: creation problems suggest Creational patterns, composition problems suggest Structural patterns, and communication or algorithm problems suggest Behavioral patterns. It is a starting point, not a decision by itself.
Applying the map
Treat each flowchart as a shortlist generator, not a prescription. Test a candidate against the concrete example, identify the closest alternative, and check whether the added abstraction is worth its indirection.
Creational Patterns: Which Factory Do I Need?
The most common confusion in this family is Factory Method vs Abstract Factory vs Builder. They all create objects, but for different reasons.
| Dimension | Factory Method | Abstract Factory | Builder | Singleton | Prototype |
|---|---|---|---|---|---|
| Core problem | Which subclass to instantiate? | Which family of products? | Too many constructor params? | Need exactly one instance? | Expensive object creation? |
| Varies what? | One product type | Entire product family | Construction steps | N/A (access control) | Source object to clone |
| Complexity | Low | Medium | Low | Low (but tricky concurrency) | Low |
| Common domain | Notifications, parsers | UI themes, cloud SDKs | HTTP requests, queries | Config, connection pool | Game entities, document templates |
| Recognition cue | A client should not choose the concrete product directly | Several products must come from a consistent family | Construction has many optional or ordered parts | A single shared instance is a deliberate constraint | Cloning is cheaper or safer than reconstructing from scratch |
A useful rule of thumb: start with Factory Method when one product type varies. Move to Abstract Factory when related products must stay consistent as a family, such as a UI toolkit whose buttons, checkboxes, and dialogs share a theme.
Structural Patterns: Wrapping, Composing, or Simplifying?
Structural patterns all deal with object composition, but their intents differ. Use this flowchart when deciding whether to translate, separate, group, extend, simplify, share, or control access.
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with SDEpedia Premium.
Related Articles
The factory method replaces direct constructor calls with a method that subclasses can override to return different types. Callers depend on an abstraction, not a concrete class.
The strategy pattern extracts a family of algorithms behind an interface so the client can swap behaviors at runtime without touching the context class.
The observer pattern decouples event producers from consumers. A subject notifies all registered observers of state changes without knowing who they are or what they do.
The decorator pattern wraps objects to add behavior at runtime without modifying the original class. Stack decorators like layers, each adding one responsibility while keeping the same interface.