Skip to content

Design Patterns Quick Reference

A pattern is a name for a structure that solves a recurring requirement, plus the reason it exists. Learn the reason and you will reach for the right one. Learn the name alone and you will add structure the problem did not ask for.

Pairs with Module 15 — SOLID and Design Patterns


The patterns this course uses, and the requirement that earns each

Pattern Earned by this requirement The alternative to consider
Strategy One behaviour varies and must be replaceable — a policy, a rate, an ordering A lambda or a comparator; a virtual function on the type itself
Factory (method / function) Object creation must depend on configuration or input, not on a literal new A free function; a switch in one place
Abstract factory Whole families of related objects must be chosen together A registry of factory functions; templates
Observer Subscribers must be notified without the subject knowing their types A callback list; a queue the loop drains; polling
Composite A part and a whole must be treated uniformly (trees, expressions, groups) A flat list plus a separate "group" concept
Decorator Behaviour must be added without changing the object's interface or class A subclass; a boolean flag in the constructor
Command Operations must be objects: undo, queueing, replay, logging A function pointer, unless you need state between phases
State Behaviour depends on a mode, and illegal transitions must be impossible An enum plus guard conditions
Adapter An existing type must present an interface the caller already expects Change the caller; wrap in a free function
Template method A fixed algorithm skeleton with a few variable steps A strategy + a free function that calls it
Chain of responsibility A request should be handled by the first stage that can, and passed on otherwise A pipeline of strategies that each return "unchanged"
Visitor Operations over a closed set of types must be added without editing them Virtual functions on each type
Registry Named things must be discovered and created without a central list A static array consulted in order
Policy-based design The choice can be fixed at compile time, and should cost nothing Runtime strategies behind interfaces; a template parameter

How to choose

  1. Name the requirement, not the pattern. "The fine rules vary by member category and must be testable" is a requirement. Write it down before choosing anything.
  2. Write the simple version first. An if chain is the correct design until the second or third variation appears.
  3. Look for the axis of change. What will be edited when the next feature arrives? That is what deserves an interface.
  4. Prefer the smallest structure that removes the edit. A comparator beats a strategy class hierarchy; a function beats a factory class.
  5. Record what you declined. "I considered Observer for notifications and rejected it because nothing needs to be told — the report is pulled on demand" is a stronger answer than listing patterns you used.

The three questions for any pattern

Question Why it matters
Which requirement earns this? Without one, you have added indirection for free
What did I consider instead? The pattern is rarely the only answer, and the reasoning is marked
What does it cost? One more indirection; more files to follow; a new implementer must find it

Quick shapes

Strategy — behaviour behind an interface, injected:

class LendingPolicy { public: virtual ~LendingPolicy() = default;
                              virtual int loanDays(const Book&) const = 0; };

class Library
{
public:
    explicit Library(std::unique_ptr<LendingPolicy> policy) : policy_(std::move(policy)) {}
private:
    std::unique_ptr<LendingPolicy> policy_;
};

Observer — subscribe, notify, unsubscribe:

class Listener { public: virtual ~Listener() = default; virtual void onEvent(const Event&) = 0; };

class Notifier
{
public:
    void subscribe(Listener& l)   { listeners_.push_back(&l); }
    void unsubscribe(Listener& l) { listeners_.erase(std::remove(listeners_.begin(), listeners_.end(), &l), listeners_.end()); }
    void notify(const Event& e)   { for (auto* l : listeners_) { l->onEvent(e); } }
private:
    std::vector<Listener*> listeners_;    // non-owning: lifetime is the design question
};

Composite — a leaf and a group answer the same question:

class Node { public: virtual ~Node() = default; virtual double total() const = 0; };
class Leaf  : public Node { /* total() is its own value */ };
class Group : public Node { std::vector<std::unique_ptr<Node>> children_; /* total() sums them */ };

Command — an operation as an object, with undo:

class Command { public: virtual ~Command() = default;
                        virtual void execute() = 0;
                        virtual void undo()    = 0; };

State — the phase decides what is legal:

class Machine;                                  // forward declaration
class State { public: virtual ~State() = default; virtual void enterCoin(Machine&) = 0; };

Anti-patterns to recognise by name

Name What it looks like Why it hurts
Singleton A global instance with a getInstance() Hidden dependency, untestable, order-of-initialisation problems
God object One class that knows everything and does everything Every change risks everything; it cannot be tested in isolation
Anemic model A class with only getters and setters, and logic elsewhere Data and behaviour separated: the encapsulation was for nothing
Object orgy Every object reaches through others to their internals Coupling grows quadratically; one change breaks many call sites
Poltergeist A class that appears only to pass calls along Indirection with no added meaning
Speculative generality Interfaces, factories and hooks for variations that never arrive More code, more to read, nothing gained

Checklist before you add a structure

  • [ ] Can I state the requirement in one sentence, without naming a pattern?
  • [ ] Is the simple version genuinely insufficient now — not hypothetically?
  • [ ] Did I consider at least one alternative and write down why it lost?
  • [ ] Does the added indirection remove an edit that would otherwise be needed?
  • [ ] Could a reviewer find the seam without being told where it is?

Related: SOLID · Class Design · Advanced projects · Module 15 — SOLID and Design Patterns