Introduction to Design Patterns
Introduction to Design Patterns
You have written object-oriented code, applied SOLID principles, used generics and streams, and wrangled concurrency. You know how to write Java. Design patterns answer a different question: given a recurring structural problem, what is the proven, idiomatic way to solve it? This lesson answers that question and maps the landscape of the 23 canonical patterns introduced by the Gang of Four.
What Is a Design Pattern?
A design pattern is a named, reusable solution to a commonly occurring problem in a given context. The term was popularised in 1994 by the book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides — universally known as the Gang of Four (GoF). The book catalogued 23 patterns with:
- A name — a shared vocabulary so teams can communicate intent instantly.
- The problem — the context and forces that demand the pattern.
- The solution — the abstract structural description (participants, collaborations).
- The consequences — trade-offs in flexibility, complexity, and performance.
Why Design Patterns Matter
Experienced engineers reach for patterns because they solve real professional pain points.
Shared Vocabulary
Saying "use a Strategy here" in a code review instantly communicates structure, intent, and expected trade-offs. Without patterns, the same discussion takes paragraphs of prose.
Proven Trade-Off Analysis
Every pattern comes with documented consequences. The Singleton saves memory but introduces global mutable state and complicates testing. Knowing the trade-offs up front prevents architectural regret later.
Guidance When Requirements Change
Patterns anticipate the axes along which software evolves. The Open/Closed Principle is aspirational; patterns are the mechanics that make it achievable. The Decorator pattern, for example, lets you add responsibilities to objects without touching existing classes — critical in codebases you cannot safely modify.
A Framework for Recognising Smells
Knowing patterns makes their absence visible. A switch on a type field scattered across dozens of methods is a signal that the Strategy or Visitor pattern is missing. You can name what is wrong and articulate the fix.
The Three GoF Categories
The 23 GoF patterns are divided into three categories based on what aspect of object structure they address.
1. Creational Patterns
Creational patterns are concerned with how objects are created. They decouple the creation mechanism from the code that uses the object, giving you flexibility over what is created, who creates it, and when.
- Singleton — ensures a class has exactly one instance and provides a global access point.
- Factory Method — defines an interface for creating an object but lets subclasses decide which class to instantiate.
- Abstract Factory — provides an interface for creating families of related objects without specifying concrete classes.
- Builder — separates the construction of a complex object from its representation, allowing the same construction process to produce different results.
- Prototype — creates new objects by copying an existing object (cloning).
2. Structural Patterns
Structural patterns are concerned with how classes and objects are composed to form larger structures. They make it easier to combine independent pieces without tight coupling.
- Adapter — converts the interface of a class into another interface clients expect.
- Bridge — separates an abstraction from its implementation so both 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 — uses sharing to efficiently support a large number of fine-grained objects.
- Proxy — provides a surrogate or placeholder for another object to control access.
3. Behavioral Patterns
Behavioral patterns are concerned with algorithms and the assignment of responsibility between objects. They describe how objects communicate and distribute work.
- Chain of Responsibility — passes a request along a chain of handlers.
- Command — encapsulates a request as an object, allowing parameterization and undo.
- Interpreter — defines a grammar and an interpreter for a language.
- Iterator — provides a way to sequentially access elements of a collection without exposing its internal representation.
- Mediator — defines an object that encapsulates how a set of objects interact.
- Memento — captures and externalises an object's internal state so it can be restored later.
- Observer — defines a one-to-many dependency so that when one object changes state all dependents are notified.
- State — allows an object to alter its behaviour 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 in a base class, deferring some steps to subclasses.
- Visitor — lets you define a new operation on elements of a structure without changing the classes of those elements.
Patterns Are Context-Dependent
No pattern is universally correct. Applying a pattern where it is not warranted adds accidental complexity — an anti-pattern in its own right. Before reaching for a pattern, verify two things:
- The problem you are facing genuinely recurs and matches the pattern's stated problem context.
- The trade-offs (typically more classes, more indirection) are worth the flexibility gained.
Patterns in the Java Ecosystem
Design patterns are not academic exercises — they are deeply embedded in the Java platform and its most important frameworks:
- Iterator — every
java.util.Collectionexposes one viaIterable. - Decorator —
java.io.BufferedInputStream,java.io.GZIPOutputStream. - Factory Method —
List.of(),Optional.of(),Path.of(). - Singleton —
Runtime.getRuntime(), Spring's default bean scope. - Proxy — Spring AOP, JDK dynamic proxies for interfaces.
- Observer —
java.util.EventListener, reactive frameworks (Project Reactor, RxJava). - Template Method — Spring's
JdbcTemplate,RestTemplate. - Builder —
StringBuilder,Stream.Builder, Lombok's@Builder.
Recognising these patterns in production libraries transforms you from a user of the API into someone who understands the architecture behind it — a critical distinction at the senior and staff engineer level.
Summary
A design pattern is a named, proven solution to a recurring design problem. The GoF catalogued 23 patterns in three categories: creational (object creation), structural (composition), and behavioral (communication and responsibility). Patterns give teams a shared vocabulary, encode hard-won trade-off knowledge, and guide designs toward extensibility. They are most valuable when applied in response to a real design pressure — not preemptively. In the following lessons you will implement each category's most important patterns in idiomatic Java 17, learning not just the structure but the forces that justify each choice.