Design Patterns
Design Patterns Overview
A design pattern is a named, reusable solution to a recurring object-oriented design problem — not a library to import, but a shape to recognize and adapt. The value is the shared vocabulary as much as the code.
- A pattern has four parts: a name, the problem it addresses, the solution shape (a structure of classes/objects and their relationships), and the consequences (trade-offs of using it)
- The Gang of Four (GoF) catalog groups 23 classic patterns into three families: creational (object creation), structural (object composition), behavioral (object interaction and responsibility)
- Patterns codify "favor composition over inheritance" and "program to an interface, not an implementation" — most patterns are specific applications of these two principles
- A pattern is a starting point, not a mandate — applying one where the problem doesn't call for it adds indirection and complexity for no benefit (Anti Patterns And Pattern Misuse)
- Recognizing a pattern in someone else's code is often more valuable day-to-day than writing one from scratch — it tells you what to expect from the design
The historical context matters for understanding why the catalog looks the way it does: it was written against Smalltalk and C++ in the early 1990s, languages without lambdas, without first-class functions, and (in C++'s case) without garbage collection. Several GoF patterns exist specifically to work around the absence of a language feature — Strategy and Command are largely replaced by a lambda in modern Java for the simple cases, and Iterator is built into every language with a for-each loop. The patterns aren't obsolete, but a fair number of their simplest use cases now have lighter-weight solutions.
| Family | Concerned with | Examples |
|---|---|---|
| Creational | how objects get created, hiding the concrete class from the caller | Factory Method, Builder, Singleton (Creational Patterns) |
| Structural | how classes and objects are composed into larger structures | Adapter, Decorator, Facade (Structural Patterns) |
| Behavioral | how objects communicate and distribute responsibility | Strategy, Observer, Command (Behavioral Patterns I) |
// "Program to an interface, not an implementation":
List<String> names = new ArrayList<>(); // caller depends on List, not ArrayList
// "Favor composition over inheritance":
class Car {
private final Engine engine; // Car HAS-A Engine — swap engines freely
Car(Engine engine) { this.engine = engine; }
}
// vs. a rigid class hierarchy: class ElectricCar extends Car { ... } — locked in at compile time