In 1994 four authors published Design Patterns: Elements of Reusable Object-Oriented Software, which catalogued 23 patterns and gave the industry a shared design vocabulary. They're called the Gang of Four (GoF) simply because there were four of them. When people say "the classic design patterns", they usually mean this list.
The authors#
The four authors came from both industry and academia.
| Author | Background |
|---|---|
| Erich Gamma | Swiss computer scientist; later co-created JUnit, led development tools at Eclipse, and works at Microsoft on VS Code |
| Richard Helm | Worked at IBM Research; brought an industry perspective |
| Ralph Johnson | Professor at the University of Illinois; the academic of the group |
| John Vlissides | Worked at IBM Research and wrote widely on applying patterns well; died in 2005 |
They kept seeing the same problems and the same solutions across object-oriented systems, without shared names for them. So they catalogued them. The book was published by Addison-Wesley in October 1994.
What made the book influential#
Three choices made the book last.
- They discovered rather than invented. The patterns already existed in real code. GoF named and documented them, like biologists cataloguing species.
- They used a consistent template. Name and classification, intent, also known as, motivation, applicability, structure, participants, collaborations, consequences, implementation, sample code, known uses, related patterns. See How to Read a Design Pattern.
- They gave developers a language. Before: "I made a class with a private constructor that returns the same instance every time..." After: "I used a Singleton."
The 23 patterns#
The book groups its patterns into three families by the problem they solve.
Creational (5): how objects are created#
| # | Pattern | Analogy | Typical use |
|---|---|---|---|
| 1 | Singleton | One president per country | Shared config, connection pool |
| 2 | Factory Method | Each pizza franchise makes its own style | Creating platform-specific UI buttons |
| 3 | Abstract Factory | A furniture line where every piece matches | Cross-platform UI toolkits |
| 4 | Builder | Assembling a sandwich step by step | SQL query builders |
| 5 | Prototype | Cloning | Spawning many similar game enemies |
Structural (7): how objects are connected#
| # | Pattern | Analogy | Typical use |
|---|---|---|---|
| 6 | Adapter | Travel power-plug adapter | Wrapping a third-party library |
| 7 | Bridge | One remote, many devices | Database drivers |
| 8 | Composite | Folders inside folders | File systems, UI trees |
| 9 | Decorator | Coffee with add-ons | Buffered I/O streams (io.BufferedReader) |
| 10 | Facade | A restaurant waiter | Simplifying a complex API |
| 11 | Flyweight | Chess pieces sharing one icon | Characters in a text editor |
| 12 | Proxy | A credit card standing in for your bank account | Lazy-loading images |
Behavioral (11): how objects communicate#
| # | Pattern | Analogy | Typical use |
|---|---|---|---|
| 13 | Chain of Responsibility | Approval chain in a company | Middleware pipelines |
| 14 | Command | A restaurant order ticket | Undo/redo |
| 15 | Interpreter | Translating a language | Parsing small languages (regex, query DSLs) |
| 16 | Iterator | Channel up/down on a TV remote | for-each loops |
| 17 | Mediator | Air traffic control | Chat room server |
| 18 | Memento | Game save points | Undo snapshots |
| 19 | Observer | Newsletter subscription | Event listeners |
| 20 | State | Vending machine modes | TCP connection states |
| 21 | Strategy | Choosing how to travel | Pluggable sorting or pricing |
| 22 | Template Method | A recipe with variations | Framework hooks |
| 23 | Visitor | A health inspector visiting each restaurant | Compiler passes over an AST |
Before and after GoF#
The book changed how developers talk about design.
| Before (pre-1994) | After |
|---|---|
| No common vocabulary; same solutions, different names | A shared language for design |
| Knowledge was hard to share | Faster communication and onboarding |
| Books explained how but rarely why | Clear problem → solution → trade-off mapping |
How the patterns fare today#
Used constantly: Iterator (built into most languages), Observer (every GUI and event system), Factory Method, Strategy, Singleton.
Most misused:
- Singleton, which creates hidden global dependencies.
- Factory, which over-engineers simple object creation.
Rarely hand-written: Interpreter (narrow use case), Visitor (powerful but complex), Flyweight (only worth it with very large numbers of objects).
Criticisms worth knowing:
- Some patterns are workarounds for missing language features. First-class functions make Strategy and Command much lighter, for example.
- Applied blindly, patterns lead to over-engineering.
- The 1994 examples feel dated.
The core problems haven't changed, though, and the names are still the common vocabulary.
You already use GoF patterns#
Everyday Python code is full of GoF patterns, even if nobody names them:
import io
import logging
from abc import ABC, abstractmethod
names = ["bob", "Alice", "carol"]
# Iterator: every for loop walks an iterator
for name in names:
print(name)
# Observer: a logger notifies every handler attached to it
logger = logging.getLogger("app")
logger.addHandler(logging.StreamHandler())
logger.warning("disk almost full")
# Decorator: BufferedReader wraps a raw stream and adds buffering
raw = io.BytesIO(b"hello")
reader = io.BufferedReader(raw)
# Strategy: the comparison (key function) is passed in
names.sort(key=str.lower)
# Template Method: the base class fixes the order of steps
class Game(ABC):
@abstractmethod
def initialize(self) -> None: ...
@abstractmethod
def start_play(self) -> None: ...
@abstractmethod
def end_play(self) -> None: ...
def play(self) -> None: # subclasses shouldn't override this
self.initialize()
self.start_play()
self.end_play()
Key takeaways#
- GoF = Gamma, Helm, Johnson, Vlissides; their 1994 book catalogued 23 patterns.
- The split is 5 creational, 7 structural, 11 behavioral.
- They documented existing practice and gave it names and a consistent template.
- A small subset (Iterator, Observer, Factory, Strategy, Singleton, Decorator) covers most everyday code.
- Modern languages make some patterns lighter, but the vocabulary still matters.