ENGIMY.IO - CHEATSHEET
DESIGN PATTERNS × QUICK REFERENCE
REFERENCE v1.0

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
← Back to All Cheatsheets