Unlocking 23 Essential Design Patterns: When, Why, and How to Use Them
Design patterns are proven, reusable solutions to common software design problems, and this comprehensive guide explains their definitions, classifications, key concepts, real‑world examples, code snippets, and best‑practice principles, helping developers choose the right pattern for any scenario.
23 Design Patterns Overview
Design patterns are a set of repeatedly used, well‑known, classified code design experiences. Using design patterns improves code reuse, readability, and reliability, turning software development into an engineering discipline.
What is a pattern?
Pattern : a general solution to a recurring problem in a given context.
Context : the environment of the project.
Problem : constraints and project goals.
Solution : a reusable design that satisfies the constraints and achieves the goals.
Three categories of design patterns
Creational patterns – focus on object creation and decouple the instantiation process.
Structural patterns – combine classes or objects into larger structures.
Behavioral patterns – define how objects interact, assign responsibilities, and encapsulate algorithms.
Key points of each category
Singleton : ensure a class has only one instance and provide a global access point.
Factory Method : define an interface for creating an object, letting subclasses decide which class to instantiate.
Abstract Factory : provide an interface for creating families of related objects without specifying concrete classes.
Builder : separate the construction of a complex object from its representation.
Prototype : create new objects by copying a prototype instance.
Adapter : convert the interface of a class into another interface clients expect.
Bridge : decouple an abstraction from its implementation so they can vary independently.
Composite : compose objects into tree structures to represent part‑whole hierarchies.
Decorator : dynamically add responsibilities to an object without affecting other objects.
Facade : provide a unified interface to a set of interfaces in a subsystem.
Flyweight : use sharing to support large numbers of fine‑grained objects efficiently.
Proxy : provide a surrogate for another object to control access.
Mediator : encapsulate how a set of objects interact, promoting loose coupling.
Chain of Responsibility : give more than one object a chance to handle a request.
Command : encapsulate a request as an object, allowing parameterization and queuing.
Interpreter : define a representation for a language's grammar and an interpreter to evaluate sentences.
Iterator : provide a way to access elements of an aggregate object sequentially without exposing its underlying representation.
Observer : define a one‑to‑many dependency so that when one object changes state, all its dependents are notified.
Strategy : define a family of algorithms, encapsulate each one, and make them interchangeable.
State : allow an object to alter its behavior when its internal state changes.
Template Method : define the skeleton of an algorithm, deferring some steps to subclasses.
Visitor : represent an operation to be performed on elements of an object structure without changing the classes of those elements.
Singleton Pattern
Definition: Ensure a class has only one instance, and provide a global point of access to it.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
public static void doSomething() {
// ...
}
}Usage scenarios:
Generating unique identifiers.
Shared resources such as configuration or thread pools.
Utility classes with static methods.
Thread‑unsafe version:
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}Solution: add synchronized to the accessor or use the eager‑initialization version shown above.
Factory Pattern
Definition: Define an interface for creating an object, but let subclasses decide which class to instantiate.
public class ConcreteCreator extends Creator {
public <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
// handle exception
}
return (T) product;
}
}Simple factory: a static method that returns a product without exposing a creator class.
Abstract Factory Pattern
Definition: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
public abstract class AbstractCreator {
public abstract AbstractProductA createProductA();
public abstract AbstractProductB createProductB();
}Template Method Pattern
Definition: Define the skeleton of an algorithm in an operation, deferring some steps to subclasses.
Key concepts: abstract class defines final template method and abstract primitive operations that subclasses implement.
Builder Pattern
Definition: Separate the construction of a complex object from its representation so that the same construction process can create different representations.
Roles:
Product – the complex object being built.
Builder – abstract interface for creating parts of the product.
ConcreteBuilder – implements Builder and assembles the product.
Director – orchestrates the building process.
Proxy Pattern
Definition: Provide a surrogate or placeholder for another object to control access to it.
Roles:
Subject – abstract interface.
RealSubject – the actual object.
Proxy – controls access to RealSubject.
Prototype Pattern
Definition: Specify the kinds of objects to create using a prototypical instance, and create new objects by copying this prototype.
public class PrototypeClass implements Cloneable {
@Override
public PrototypeClass clone() {
PrototypeClass clone = null;
try {
clone = (PrototypeClass) super.clone();
} catch (CloneNotSupportedException e) {
// handle exception
}
return clone;
}
}Advantages: high performance, avoids constructor constraints.
Mediator Pattern
Definition: Encapsulate how a set of objects interact, promoting loose coupling.
public abstract class Mediator {
protected ConcreteColleague1 c1;
protected ConcreteColleague2 c2;
public abstract void doSomething1();
public abstract void doSomething2();
// getters and setters for colleagues
}Chain of Responsibility Pattern
Definition: Give more than one object a chance to handle a request, passing the request along a chain until an object handles it.
public abstract class Handler {
private Handler nextHandler;
public final Response handleMessage(Request request) {
Response response = null;
if (this.getHandlerLevel().equals(request.getRequestLevel())) {
response = this.echo(request);
} else if (nextHandler != null) {
response = nextHandler.handleMessage(request);
}
return response;
}
public void setNext(Handler handler) { this.nextHandler = handler; }
protected abstract Level getHandlerLevel();
protected abstract Response echo(Request request);
}Decorator Pattern
Definition: Dynamically attach additional responsibilities to an object without affecting other objects.
Roles:
Component – abstract interface.
ConcreteComponent – core object.
Decorator – abstract class holding a Component reference.
ConcreteDecorator – adds behavior.
Strategy Pattern
Definition: Define a family of algorithms, encapsulate each one, and make them interchangeable.
public enum Calculator {
ADD("+") {
public int exec(int a, int b) { return a + b; }
},
SUB("-") {
public int exec(int a, int b) { return a - b; }
};
private String value;
private Calculator(String v) { this.value = v; }
public String getValue() { return value; }
public abstract int exec(int a, int b);
}Adapter Pattern
Definition: Convert the interface of a class into another interface clients expect.
Roles:
Target – the desired interface.
Adaptee – existing class with an incompatible interface.
Adapter – implements Target and translates calls to Adaptee.
Iterator Pattern
Definition: Provide a way to access the elements of an aggregate object sequentially without exposing its underlying representation.
Composite Pattern
Definition: Compose objects into tree structures to represent part‑whole hierarchies.
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public void add(Component c) { children.add(c); }
public void remove(Component c) { children.remove(c); }
public List<Component> getChildren() { return children; }
}Observer Pattern
Definition: Define a one‑to‑many dependency so that when one object changes state, all its dependents are notified.
public abstract class Subject {
private Vector<Observer> observers = new Vector<>();
public void addObserver(Observer o) { observers.add(o); }
public void delObserver(Observer o) { observers.remove(o); }
public void notifyObservers() {
for (Observer o : observers) { o.update(); }
}
}Facade Pattern
Definition: Provide a unified interface to a set of interfaces in a subsystem.
Memento Pattern
Definition: Capture and externalize an object's internal state so that it can be restored later without violating encapsulation.
Visitor Pattern
Definition: Represent an operation to be performed on the elements of an object structure without changing the classes of the elements.
State Pattern
Definition: Allow an object to alter its behavior when its internal state changes.
Interpreter Pattern
Definition: Define a representation for a language's grammar and an interpreter that uses the representation to interpret sentences.
Flyweight Pattern
Definition: Use sharing to support large numbers of fine‑grained objects efficiently.
public class FlyweightFactory {
private static Map<String, Flyweight> pool = new HashMap<>();
public static Flyweight getFlyweight(String key) {
Flyweight fw = pool.get(key);
if (fw == null) {
fw = new ConcreteFlyweight(key);
pool.put(key, fw);
}
return fw;
}
}Bridge Pattern
Definition: Decouple an abstraction from its implementation so that the two can vary independently.
Design Principles
Single Responsibility Principle
Each class or module should have only one reason to change, improving readability, maintainability, and reducing risk.
Liskov Substitution Principle
Objects of a superclass shall be replaceable with objects of a subclass without affecting correctness.
Interface Segregation Principle
Prefer many specific interfaces over a single, fat interface.
Dependency Inversion Principle
High‑level modules should not depend on low‑level modules; both should depend on abstractions.
Open/Closed Principle
Software entities should be open for extension but closed for modification.
Least Knowledge Principle (Law of Demeter)
Each unit should only talk to its immediate friends; avoid chaining calls like a.b.c().
By following these principles and the patterns above, developers can build flexible, reusable, and maintainable software systems.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Intelligent Backend & Architecture
We share personal insights on intelligent, automated backend technologies, along with practical AI knowledge, algorithms, and architecture design, grounded in real business scenarios.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
