Design Patterns 101: Why the Gang of Four Changed Software Forever¶
Let me paint you a picture. It’s 1993. You’re a software developer. You’ve just spent three weeks building an elegant notification system. It’s beautiful. It works. You’re proud of it.
Then your colleague walks over, looks at your screen, and says: “Oh, you built an Observer.”
Wait, what?
Turns out, the problem you solved? Thousands of developers before you solved the exact same one. And they all arrived at roughly the same solution. You didn’t invent anything, you just didn’t know there was already a name for it.
That is the core idea behind design patterns: naming solutions to problems that keep showing up, over and over, in software development. And in 1994, four very smart people decided to write them all down.
The Gang of Four: A Brief Origin Story¶
In 1994, four authors (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) published a book that would change software engineering forever: “Design Patterns: Elements of Reusable Object-Oriented Software.”
These four became known as the Gang of Four (GoF), which sounds like either a programming legends group or a heist movie crew. Either way, the book delivered.
They cataloged 23 design patterns, organized into three categories. The book became one of the most influential texts in software engineering history. Over 30 years later, these patterns are still taught in every serious CS program, asked about in interviews, and used daily by developers worldwide.
“The Gang of Four didn’t invent these patterns. They discovered them, like biologists cataloging species that already existed in the wild.”
So What Exactly IS a Design Pattern?¶
A design pattern is a general, reusable solution to a commonly occurring problem in software design. Think of it as a blueprint, not finished code. You cannot copy-paste a design pattern into your project, it’s a template that shows you how to structure your solution.
Here’s an analogy. Think about architecture (the building kind, not the software kind). An architect does not reinvent the concept of a “doorway” for every building. Instead, they draw on established patterns:
- Double doors for high traffic areas
- Revolving doors for climate control
- Sliding doors for tight spaces
Each is a known solution to a known problem. Software design patterns work the same way. You have a problem? There is probably a pattern for that.
The Three Categories¶
The GoF organized their 23 patterns into three categories based on what kind of problem they solve:
| Category | What It Deals With | How Many |
|---|---|---|
| Creational | How objects get created, making sure you create objects in a way that’s suitable to the situation | 5 |
| Structural | How objects are composed, building relationships between objects to form larger, flexible structures | 7 |
| Behavioral | How objects communicate, defining how objects interact and distribute responsibility among themselves | 11 |
Let’s break these down so they actually make sense.
Creational Patterns: “How Do I Build This Thing?”¶
You might think creating an object is simple, just slap a new keyword and you’re done. But in real applications, object creation can get surprisingly complex:
- What if you need to ensure only ONE instance exists? (Singleton)
- What if the object has 15 optional parameters? (Builder)
- What if you don’t know which exact type to create until runtime? (Factory Method)
- What if you need to create families of related objects that work together? (Abstract Factory)
- What if creating a new object is expensive and you’d rather clone an existing one? (Prototype)
Creational patterns give you battle-tested ways to handle all of these situations.
Structural Patterns: “How Do I Organize These Pieces?”¶
Once you have your objects, you need to compose them into larger structures. Structural patterns help you build these relationships cleanly:
- Your old API doesn’t match what your new code expects? Wrap it. (Adapter)
- You want to add new behavior to an object without changing it? Layer it. (Decorator)
- Your subsystem has 47 classes and the client just wants ONE simple method? Simplify it. (Facade)
- You have thousands of similar objects eating all your RAM? Share them. (Flyweight)
These patterns are all about making objects play nicely together without creating tangled messes.
Behavioral Patterns: “How Should These Things Talk to Each Other?”¶
This is the largest category (11 patterns!) because communication between objects is where most of the complexity lives:
- One object changes and a bunch of others need to know? (Observer)
- You need to swap algorithms at runtime without if/else chains? (Strategy)
- You want undo/redo functionality? (Command + Memento)
- You need to process a request through a chain of handlers? (Chain of Responsibility)
Behavioral patterns keep your objects communicating without becoming a tangled web of dependencies.
All 23 Patterns at a Glance¶
Here is the complete roster. Think of this as your field guide, you don’t need to memorize every one right now, but it is incredibly useful to know they exist so you can look them up when you hit the right problem.
Creational Patterns (5)¶
| Pattern | What It Does (One-Liner) |
|---|---|
| Abstract Factory | Creates families of related objects without specifying their concrete classes |
| Builder | Constructs complex objects step by step, separating construction from representation |
| Factory Method | Defines an interface for creating objects, letting subclasses decide which class to instantiate |
| Prototype | Creates new objects by cloning an existing object (the prototype) |
| Singleton | Ensures a class has only one instance and provides a global access point to it |
Structural Patterns (7)¶
| Pattern | What It Does (One-Liner) |
|---|---|
| Adapter | Converts the interface of a class into another interface clients expect |
| Bridge | Separates an abstraction from its implementation so the two can vary independently |
| Composite | Composes objects into tree structures to represent part-whole hierarchies |
| Decorator | Attaches additional responsibilities to an object dynamically |
| Facade | Provides a simplified interface to a complex subsystem |
| Flyweight | Shares fine-grained objects efficiently to support large numbers of similar objects |
| Proxy | Provides a surrogate or placeholder for another object to control access to it |
Behavioral Patterns (11)¶
| Pattern | What It Does (One-Liner) |
|---|---|
| Chain of Responsibility | Passes a request along a chain of handlers until one handles it |
| Command | Encapsulates a request as an object, allowing parameterization, queuing, and undo |
| Interpreter | Defines a grammar and an interpreter for a language |
| Iterator | Provides a way to access elements of a collection sequentially without exposing its underlying representation |
| Mediator | Defines an object that encapsulates how a set of objects interact |
| Memento | Captures and restores an object’s internal state without violating encapsulation |
| Observer | Defines a one-to-many dependency so that when one object changes state, all its dependents are notified |
| State | Allows an object to alter its behavior when its internal state changes |
| Strategy | Defines a family of algorithms, encapsulates each one, and makes them interchangeable |
| Template Method | Defines the skeleton of an algorithm, letting subclasses override specific steps |
| Visitor | Lets you define new operations on elements of a structure without changing the elements themselves |
Complete Quick Reference¶
For the visual thinkers, here is every single pattern in one numbered table:
| # | Pattern | Category | Key Purpose |
|---|---|---|---|
| 1 | Abstract Factory | Creational | Families of related objects |
| 2 | Builder | Creational | Step-by-step complex object construction |
| 3 | Factory Method | Creational | Delegate instantiation to subclasses |
| 4 | Prototype | Creational | Clone existing objects |
| 5 | Singleton | Creational | Single instance with global access |
| 6 | Adapter | Structural | Interface compatibility |
| 7 | Bridge | Structural | Separate abstraction from implementation |
| 8 | Composite | Structural | Tree structures, part-whole hierarchies |
| 9 | Decorator | Structural | Dynamic responsibility attachment |
| 10 | Facade | Structural | Simplified subsystem interface |
| 11 | Flyweight | Structural | Shared fine-grained objects |
| 12 | Proxy | Structural | Controlled access surrogate |
| 13 | Chain of Responsibility | Behavioral | Pass request along handler chain |
| 14 | Command | Behavioral | Encapsulate request as object |
| 15 | Interpreter | Behavioral | Language grammar and interpretation |
| 16 | Iterator | Behavioral | Sequential collection access |
| 17 | Mediator | Behavioral | Centralized object interaction |
| 18 | Memento | Behavioral | Capture and restore state |
| 19 | Observer | Behavioral | One-to-many state change notification |
| 20 | State | Behavioral | Behavior changes with internal state |
| 21 | Strategy | Behavioral | Interchangeable algorithms |
| 22 | Template Method | Behavioral | Algorithm skeleton with overridable steps |
| 23 | Visitor | Behavioral | New operations without changing elements |
When to Use Patterns vs. When NOT To¶
This is the part most tutorials skip, but it might be the most important section in this entire article. Design patterns are powerful, but they are also dangerously easy to overuse. There is even a name for it: Pattern Fever.
Use Patterns When:¶
- You recognize a recurring problem that a pattern directly addresses
- The codebase is growing and needs structure to stay maintainable
- You need flexibility for future requirements (swappable algorithms, pluggable components)
- Multiple team members need a shared vocabulary to discuss design decisions
- You are building a library or framework that others will extend
Do NOT Use Patterns When:¶
- A simple solution works fine, seriously, a 10-line function does not need a Strategy pattern
- You are speculating about future requirements (YAGNI, You Aren’t Gonna Need It)
- The pattern adds more complexity than it solves (this happens more often than you’d think)
- You are working on a small, throwaway script
- You are using a pattern just because you learned about it yesterday and you’re excited (we have all done this, no judgment)
The Golden Rule: If applying a pattern makes the code harder to read and understand, you are using it wrong. Patterns should simplify communication about design, not obscure it behind layers of abstraction nobody asked for.
Here is a good litmus test: if you have to explain your pattern choice with a 20-minute whiteboard session and your colleague’s eyes glaze over, you’ve probably over-engineered it.
Wrapping Up¶
Here are the key takeaways from your introduction to design patterns:
- Design patterns are templates, not rules. They are reusable solutions to recurring problems, not rigid blueprints to follow blindly.
- The Gang of Four organized 23 patterns into three categories: Creational (object creation), Structural (composition), and Behavioral (communication). Knowing the categories helps you navigate to the right pattern faster.
- Context is everything. A pattern applied in the wrong situation creates more complexity than it solves. If applying a pattern makes the code harder to read, you are using it wrong.
- Start simple, then reach for patterns when you feel the pain. Duplication, tight coupling, rigidity: these are the signals that a pattern might help.
“The best developers know when NOT to use a pattern. Start simple. When you feel the pain of a design problem (duplication, tight coupling, rigidity) reach for the pattern that addresses that specific pain.”
The journey from knowing about patterns to instinctively reaching for the right one at the right time, that is where the real growth happens.
Why don’t design patterns ever get lonely? Because they always come in a Gang of Four!
Cheat Sheet¶
Key Questions & Answers¶
What is a design pattern?¶
A design pattern is a general, reusable solution to a commonly occurring problem in software design. It’s a template, not finished code. The Gang of Four cataloged 23 patterns in 1994, organized into three categories: Creational (object creation), Structural (composition), and Behavioral (communication between objects).
Name the three categories of GoF patterns and give an example of each.¶
Creational patterns deal with object creation: Singleton ensures one instance, Factory Method lets subclasses decide which class to instantiate. Structural patterns deal with composition: Adapter makes incompatible interfaces work together, Decorator adds behavior dynamically. Behavioral patterns deal with communication: Observer notifies dependents of state changes, Strategy lets you swap algorithms at runtime.
When should you NOT use a design pattern?¶
When the simpler solution works. Patterns add abstraction and indirection. If your codebase is small or the problem is straightforward, a pattern can over-engineer the solution. Apply a pattern when you feel the pain it solves (duplication, tight coupling, rigidity), not preemptively.
Key Concepts at a Glance¶
| Question | Answer |
|---|---|
| How many GoF patterns? | 23 |
| Three categories? | Creational, Structural, Behavioral |
| Creational patterns (5)? | Singleton, Factory Method, Abstract Factory, Builder, Prototype |
| Structural patterns (7)? | Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy |
| Behavioral patterns (11)? | Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor |
| Singleton? | One instance, global access point |
| Factory Method? | Subclass decides which class to instantiate |
| Observer? | One-to-many dependency, notify all dependents when state changes |
| Strategy? | Swap algorithms at runtime via composition |
| Adapter? | Makes incompatible interfaces work together |
| Decorator? | Adds behavior dynamically without modifying the class |
| Facade? | Simplified interface to a complex subsystem |
| Pattern vs anti-pattern? | Pattern: proven solution. Anti-pattern: common bad practice disguised as a solution |
| When to apply? | When you feel the pain (duplication, coupling, rigidity), not preemptively |
Sources & Further Reading¶
- Gamma, E., Helm, R., Johnson, R. & Vlissides, J., Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley (1994)
- Freeman, E. & Robson, E., Head First Design Patterns, O’Reilly Media
- Refactoring.Guru, Design Patterns
- SourceMaking, Design Patterns
- Martin, R.C., Agile Software Development, Principles, Patterns, and Practices, Pearson
- Wikipedia, Software Design Pattern
- Dofactory, C# Design Patterns
- Microsoft Learn, Common Design Patterns