Design Patterns Quick Reference
Everything you need day‑to‑day – creational, structural, and behavioural patterns.
What are Design Patterns?
- Reusable solutions to common software design problems
- Proven, tested, and documented
- 3 categories: Creational, Structural, Behavioural
- Make code more flexible, maintainable, and scalable
- Not code – they are patterns / templates
Creational Patterns
Singleton
- Ensures only one instance of a class exists
- Global access point
- Use when: Database connections, logging, configuration
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) instance = new Singleton();
return instance;
}
}
Factory Method
- Creates objects without specifying the exact class
- Subclasses decide which class to instantiate
- Use when: Creating different types of objects
abstract class Creator {
abstract Product createProduct();
}
class ConcreteCreator extends Creator {
Product createProduct() { return new ConcreteProduct(); }
}
Abstract Factory
- Creates families of related objects
- Factory of factories
- Use when: Multiple related products
interface GUIFactory {
Button createButton();
Window createWindow();
}
class MacFactory implements GUIFactory { ... }
class WinFactory implements GUIFactory { ... }
Builder
- Constructs complex objects step by step
- Separates construction from representation
- Use when: Object has many optional parameters
new UserBuilder()
.setName("Alice")
.setAge(25)
.setEmail("alice@ex.com")
.build();
Prototype
- Creates objects by cloning an existing object
- Reduces subclassing
- Use when: Object creation is expensive
class Prototype implements Cloneable {
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Object Pool
- Reuses objects from a pool (not in GoF)
- Reduces object creation overhead
- Use when: Reusing expensive objects (DB connections)
Structural Patterns
Adapter
- Converts one interface to another
- Allows incompatible interfaces to work together
- Use when: Integrating legacy systems
interface Target { void request(); }
class Adaptee { void specificRequest(); }
class Adapter implements Target {
private Adaptee adaptee;
public void request() { adaptee.specificRequest(); }
}
Decorator
- Adds behaviour dynamically to an object
- Alternative to subclassing
- Use when: Adding functionality at runtime
interface Component { void operation(); }
class ConcreteComponent implements Component { ... }
class Decorator implements Component {
protected Component component;
public void operation() { component.operation(); }
}
Facade
- Simplifies complex subsystem
- Provides a unified interface
- Use when: Complex libraries or frameworks
class Facade {
private SubsystemA a;
private SubsystemB b;
void operation() { a.doA(); b.doB(); }
}
Proxy
- Controls access to another object
- Virtual, protection, remote proxy
- Use when: Lazy loading, access control
interface Subject { void request(); }
class RealSubject implements Subject { ... }
class Proxy implements Subject {
private RealSubject real;
void request() { if(real==null) real=new RealSubject(); real.request(); }
}
Composite
- Composes objects into tree structures
- Treats individual and composite objects uniformly
- Use when: Hierarchical structures (UI, file system)
interface Component { void operation(); }
class Leaf implements Component { ... }
class Composite implements Component {
List children = new ArrayList<>();
void operation() { for(Component c: children) c.operation(); }
}
Bridge
- Separates abstraction from implementation
- Both can vary independently
- Use when: Platform‑independent code
Flyweight
- Shares objects to reduce memory usage
- Intrinsic vs extrinsic state
- Use when: Many fine‑grained objects
Module / Facade (JavaScript)
- Encapsulates implementation
- Exposes public API
- Use when: Organising code
Behavioural Patterns
Observer
- One‑to‑many dependency between objects
- When one changes, all dependents are notified
- Use when: Event handling, pub‑sub
interface Observer { void update(); }
class Subject {
List observers = new ArrayList<>();
void attach(Observer o) { observers.add(o); }
void notifyAll() { for(Observer o: observers) o.update(); }
}
Strategy
- Defines a family of algorithms
- Encapsulates each algorithm
- Makes them interchangeable
- Use when: Multiple algorithms (sorting, payment)
interface Strategy { void execute(); }
class ConcreteStrategyA implements Strategy { ... }
class Context { private Strategy strategy; void execute() { strategy.execute(); } }
Command
- Encapsulates a request as an object
- Parameterises clients with requests
- Use when: Undo/redo, logging, queuing
interface Command { void execute(); }
class ConcreteCommand implements Command { ... }
class Invoker { private Command command; void setCommand(Command c) { command=c; } void execute() { command.execute(); } }
Template Method
- Defines skeleton of an algorithm
- Subclasses override specific steps
- Use when: Reusing algorithm structure
abstract class Template {
final void algorithm() { step1(); step2(); step3(); }
abstract void step1();
abstract void step2();
void step3() { /* default */ }
}
State
- Object changes behaviour when its state changes
- State as an object
- Use when: State‑dependent behaviour
interface State { void handle(); }
class Context { private State state; void setState(State s) { state=s; } void request() { state.handle(); } }
Chain of Responsibility
- Passes request along a chain of handlers
- Each handler decides to process or pass
- Use when: Multiple handlers (logging, authentication)
Iterator
- Sequentially accesses elements of a collection
- Separates traversal from collection
- Use when: Iterating over collections
interface Iterator { boolean hasNext(); Object next(); }
class ConcreteIterator implements Iterator { ... }
Visitor
- Adds operations to objects without modifying them
- Double dispatch
- Use when: Operations on object structures
Mediator
- Reduces coupling between objects
- Centralises communication
- Use when: Many objects interacting
Memento
- Captures and externalises object state
- Allows undo/restore
- Use when: Undo functionality
Interpreter
- Defines a grammar for a language
- Interprets sentences in that language
- Use when: Domain‑specific languages
Null Object
- Provides a default, do‑nothing object
- Avoids null checks
- Use when: Avoiding null pointer exceptions
Pattern Comparison
| Pattern | Category | Purpose | When to Use |
|---|---|---|---|
| Singleton | Creational | Single instance | One‑of‑a‑kind objects |
| Factory | Creational | Object creation | Different product types |
| Builder | Creational | Complex object | Many optional parameters |
| Adapter | Structural | Interface conversion | Integrating legacy code |
| Decorator | Structural | Dynamic behaviour | Adding features at runtime |
| Observer | Behavioural | Event notification | Event‑driven systems |
| Strategy | Behavioural | Algorithm selection | Multiple algorithms |
| Command | Behavioural | Request encapsulation | Undo/redo, queuing |
SOLID Principles (Foundational)
- S – Single Responsibility Principle (SRP)
- O – Open/Closed Principle (OCP)
- L – Liskov Substitution Principle (LSP)
- I – Interface Segregation Principle (ISP)
- D – Dependency Inversion Principle (DIP)
Best Practices
- Choose the right pattern – don't over‑engineer.
- Understand the problem first – pattern comes from the problem.
- Don't force patterns – not everything needs a pattern.
- Keep it simple – patterns should simplify, not complicate.
- Use patterns consistently – across the team.
- Document patterns – explain why a pattern was used.
- Refactor towards patterns – when the code evolves.
- Learn from anti‑patterns – recognise what not to do.
📌 Quick Reference
Creational: Singleton, Factory, Abstract Factory, Builder, Prototype
Structural: Adapter, Decorator, Facade, Proxy, Composite, Bridge
Behavioural: Observer, Strategy, Command, Template, State, Chain, Iterator, Visitor
SOLID: SRP, OCP, LSP, ISP, DIP
Best practices: choose wisely, keep it simple, document, refactor towards patterns
📌 Quick Reference
Creational: Singleton, Factory, Abstract Factory, Builder, Prototype
Structural: Adapter, Decorator, Facade, Proxy, Composite, Bridge
Behavioural: Observer, Strategy, Command, Template, State, Chain, Iterator, Visitor
SOLID: SRP, OCP, LSP, ISP, DIP
Best practices: choose wisely, keep it simple, document, refactor towards patterns
Structural: Adapter, Decorator, Facade, Proxy, Composite, Bridge
Behavioural: Observer, Strategy, Command, Template, State, Chain, Iterator, Visitor
SOLID: SRP, OCP, LSP, ISP, DIP
Best practices: choose wisely, keep it simple, document, refactor towards patterns