What are design patterns?
A design pattern is a named solution to a problem that keeps coming back. It is not code you copy. It is a shape you adapt to the problem in front of you.
Patterns give a team a shared name for a design and carry experience from people who solved the problem before. They also make code easier to read, but only when the reader knows the pattern. The cost is indirection. A pattern that does not earn its keep makes a system harder to understand.
Categories of design patterns
Patterns are grouped by what they change: object creation, composition, or collaboration.
Creational patterns
These deal with how objects get created.
- Singleton: keeps one instance of a class and gives it a global point of access
- Factory: creates objects without naming the exact classes
- Abstract Factory: provides an interface for creating families of related objects
- Builder: separates how a complex object is built from its representation
- Prototype: creates new objects by copying an existing one
Structural patterns
These deal with how objects are composed.
- Adapter: converts a class interface into one the client expects
- Decorator: adds responsibilities to an object at runtime
- Facade: provides one simplified interface to a set of interfaces
- Proxy: stands in for another object
- Bridge: separates an abstraction from its implementation
- Composite: composes objects into trees to represent part-whole hierarchies
- Flyweight: shares data so large numbers of small objects fit in memory
Behavioral patterns
These deal with how objects collaborate and share responsibility.
- Observer: defines a one-to-many dependency so that when one object changes state, its dependents are notified
- Strategy: defines a family of algorithms, encapsulates each one, and makes them interchangeable
- Command: wraps a request as an object, which lets clients parameterize it
- State: lets an object change behavior when its internal state changes
- Template Method: defines the skeleton of an algorithm in a base class and lets subclasses override steps
- Iterator: gives sequential access to a collection without exposing its representation
- Mediator: encapsulates how a set of objects interact
- Chain of Responsibility: passes requests along a chain of handlers
- Visitor: adds operations to the elements of an object structure without changing the elements
When to use design patterns
Use a pattern when you can name the problem it solves and the change it makes cheaper. A pattern added to make code look sophisticated is just more code to read.
Common pitfalls
- Over-engineering. Don't use a pattern just because you know it.
- The wrong pattern. A pattern that doesn't fit hides the real design.
- Too many layers. Indirection has a cost, and the cost adds up.
- Rigid application. Patterns are starting points, not rules. Adapt them to the problem.
Learning more
Start with one pattern you can use this month. Read examples in code you already know. The goal is not to collect patterns. It is to recognize the situation where one applies, and to leave it alone when it does not.