Express course · No. 04
Most of them you've already reinvented by hand. A pattern is just the name — so a team can say in one word what would take a paragraph, and recognise the move before building it badly.
20 patterns · a diagram for each · cheat sheet at the end
A design pattern is a named, reusable solution to a problem that shows up again and again in code. It's vocabulary, not a library — you don't install it, you recognise it.
Design Pattern — a name for a move you already make
Footballers don't invent "the give-and-go" mid-match. It has a name, and saying the name is faster than describing the whole move.
A design pattern is a move competent developers reinvent by hand anyway. Naming it turns a paragraph of explanation into one word the whole team shares. When someone says "wrap it in a Decorator," everyone sees the shape instantly — and that is the entire point of a pattern: a shared vocabulary for moves you'd make regardless.
- What it is
- A named solution to a problem that keeps recurring in code.
- What it isn't
Not a library: you don't install it, you recognise it and write it.
- Scale
Lives inside the code of one module — unlike architectural patterns, which decide the floor plan of the whole system.
- Why
- Shared language: one word instead of a paragraph.
Gang of Four — patterns are discovered, not invented
Nobody invented the arch. Builders kept finding it was the strongest way to span a gap — so it got a name.
The Gang of Four (GoF) are the four authors of the book Design Patterns. They didn't design 23 clever tricks; they catalogued solutions that kept reappearing in good code. So a pattern isn't a target to hit — it's a shape you arrive at naturally when the problem calls for it. If you're forcing one in, you probably don't have the problem yet.
The map: three families, three questions
A kitchen has tools for three jobs: making the food, plating it, and serving it. The patterns split the same way.
Creational patterns are about how objects are born — who builds them, and how. Structural patterns are about how objects fit together into larger shapes. Behavioural patterns are about how objects talk and divide responsibility. Almost every classic pattern is one of those three answers.
Indirection — a pattern you don't need is just complexity
A Swiss Army knife in your pocket is handy. Bolting all twenty tools onto your front door is not.
Every pattern adds indirection — a layer between you and the thing. That's worth it when it buys flexibility you'll actually use, and pure cost when it doesn't. The common mistake isn't ignorance of patterns; it's reaching for one before the problem exists.
How to read each pattern
A passport: every one has the same fields, so they're easy to compare.
Every pattern from here on has the same parts: its English name (that's the term — remember it), a picture from everyday life, a diagram, and a card with fields: problem (what hurts), idea (how it solves it), example, cost (what you pay), when to use, and related patterns. At the end there's a cheat sheet with every name on one page.
A pattern is a shortcut for a conversation. Use it to be understood, not to look clever.
How objects come to life — without scattering new everywhere and welding your code to concrete classes.
Factory — ask for a thing by name, not by recipe
A coffee machine: you press "latte" and get one. You don't grind, froth, and pour yourself — and you don't need to know how it's done.
A Factory hands you an object without you calling its constructor directly, so the calling code never depends on the concrete class. It only knows the interface. It buys the freedom to change what gets built without touching who asked for it.
- Problem
new StripeProvider()is scattered through the code — welded to a class.- Idea
- Ask a factory for the object; it decides which class to build.
- Example
createPaymentProvider("stripe")returns aPaymentProvider. Switching to PayPal means changing the factory, not every call site.- Cost
- An extra layer. A factory that builds exactly one thing is a smell.
- When to use
- There are several implementations, or there will be.
- Related
- Abstract Factory — the same idea for a whole family of objects.
Abstract Factory — a whole matching family at once
Buying a furniture set — "Victorian" or "Modern" — where every piece arrives in the same style, with no mismatched chairs.
When objects must come in consistent families, an Abstract Factory builds the whole set at once so the parts fit together. Powerful — but it's heavy machinery, worth it only when the families are real.
- Problem
- Objects must match each other, and they're easy to mix up.
- Idea
- One factory produces the whole set in one style.
- Example
A UI toolkit producing matching buttons, menus and dialogs for macOS or for Windows from one factory.
- Cost
- Heavy machinery: lots of interfaces and classes.
- When to use
- Only when the families are real, and there's more than one.
- Related
Built from Factory. "An abstract factory for one product" is classic over-engineering.
Builder — assemble a complex object step by step
Ordering a custom burger — bun, patty, no onion, extra cheese — one choice at a time, then "done."
When an object has many optional parts, a Builder lets you set them piece by piece instead of a monstrous constructor with twelve arguments. At the end you call build() and get the finished object. It trades one baffling constructor for a readable chain.
- Problem
- A twelve-argument constructor, half of them optional.
- Idea
- Set the parts one at a time, then
build(). - Example
QueryBuilder().select("name").where("age > 18").limit(10).build().- Cost
- One more class next to the real one.
- When to use
- The object has many optional parts.
- Related
Factory decides what to build; Builder decides how to assemble something complex.
Singleton — exactly one, shared by all
A country has one president. Everyone who refers to "the president" means the same person — there aren't two.
A Singleton guarantees a single instance with one global access point. But handle with care: a singleton is global state in a nice coat, and global state makes testing and reasoning hard.
- Problem
- You need exactly one shared instance.
- Idea
- The class itself guarantees one instance and one access point.
- Example
- A configuration object or logger everyone reads from.
- Cost
- Global state: testing and reasoning get harder.
- When to use
Rarely. A single instance you pass in explicitly often beats one reached through a global.
- Related
- Creational like Factory, but about "how many", not "which one".
Prototype — copy a filled-in thing instead of building fresh
Photocopying a completed form is faster than filling a blank one from scratch.
When making an object from scratch is expensive or fiddly, a Prototype lets you clone an existing one and tweak it. Handy when objects are costly to construct and mostly similar.
- Problem
- Building the object from scratch is slow and fiddly.
- Idea
- Take a ready object, copy it, adjust the differences.
- Example
- Duplicating a configured game enemy, or a styled document node.
- Cost
- Copying needs care: what gets copied, and what stays shared.
- When to use
- Objects are costly to construct and mostly similar.
- Related
- An alternative to Factory: not "build", but "copy".
Hide the
new. The fewer places that know how an object is built, the freer you are to change it.
How objects compose into larger structures — fitting incompatible parts together and adding capability without a rewrite.
Adapter — a plug converter between two interfaces
Your laptop charger abroad — the device is fine, the socket is fine; you just need the little converter between them.
An Adapter wraps one interface so it looks like another, letting two things that weren't designed to cooperate work together. It's how you stop someone else's API from leaking into your whole codebase.
- Problem
Someone else's interface doesn't match yours and spreads through your code.
- Idea
- A wrapper that translates calls from one interface to another.
- Example
A third-party payment SDK wrapped so it satisfies your own
PaymentProvider.- Cost
- One more layer to update when the vendor's API changes.
- When to use
- Plugging in third-party or legacy code.
- Related
Wraps an object like Decorator and Proxy, but changes the interface.
Decorator — add toppings without changing the pizza
A plain pizza, then cheese, then mushrooms — each layer wraps the last and adds something, and it's still a pizza.
A Decorator wraps an object to add behaviour without modifying the original or subclassing it. The interface stays the same, so layers stack. It lets you add features in combinations nobody had to anticipate.
- Problem
- You need add-ons in any combination; a subclass for each won't scale.
- Idea
- Wrap the object, add one behaviour, keep the interface.
- Example
A data stream → compression → encryption; each layer can be stacked or removed.
- Cost
- Lots of small wrappers; a stack of layers is harder to debug.
- When to use
- Capabilities need to be combined at runtime.
- Related
Same shape as Proxy, but the goal is to add, not to control. The textbook case of composition over inheritance.
Facade — one simple front desk over a messy back office
A hotel concierge — you say "I need a taxi and a dinner reservation," and they handle the tangle of phone calls behind the counter.
A Facade gives a simple, single entry point to a complicated subsystem, hiding its moving parts. It shrinks a big surface down to the one door most callers need.
- Problem
- Doing one simple thing means knowing a dozen subsystem classes.
- Idea
- One simple door that orchestrates the subsystem.
- Example
VideoConverter.convert(file, "mp4")quietly orchestrates codecs, buffers and audio streams.- Cost
The complexity doesn't vanish — it's hidden. Fine control still goes around the facade.
- When to use
- Most callers need one or two simple scenarios.
- Related
Adapter changes the interface of one thing; Facade simplifies a whole subsystem.
Proxy — a stand-in that controls access
A celebrity's assistant — you don't reach the star directly; the assistant screens, schedules, and sometimes answers for them.
A Proxy stands in front of an object to control access to it — for lazy loading, permissions, caching, or talking to something remote. Same interface, an extra gate in front.
- Problem
The object is expensive to load, needs permissions, or lives on another machine.
- Idea
- A stand-in with the same interface sits in front of the real object.
- Example
An image proxy that doesn't load the real file until it's shown; an access proxy that checks permissions before forwarding the call.
- Cost
- An extra hop on every call; latency hidden from the caller.
- When to use
- Lazy loading, permissions, caching, remote objects.
- Related
- Same shape as Decorator, different goal — access control.
Composite — treat a tree and a leaf the same
A folder holds files and other folders. "Calculate the size" works the same whether you ask one file or the whole tree.
A Composite lets you treat a single object (a leaf) and a group of objects (a composite) uniformly — they share one interface. It turns recursive structures into something you handle without special-casing every level.
- Problem
- Working with a tree needs a special case at every level.
- Idea
- Leaf and branch share one interface; a branch just calls its children.
- Example
A UI where a button and a panel-full-of-buttons both answer
render()andgetSize().- Cost
The shared interface can be too general: not every operation makes sense on a leaf.
- When to use
- The data is naturally a tree: folders, UI, documents.
- Related
- Walked with Iterator; new operations are added with Visitor.
Composition over inheritance: snap behaviour together at runtime instead of freezing it into a class tree.
The first half of the behavioural patterns: how objects share work and talk to each other — so responsibility is split cleanly and the right code runs at the right moment.
Strategy — swap the algorithm, keep the caller
A maps app: same trip, but you pick "fastest," "shortest," or "avoid tolls," and it routes differently. You choose the strategy; the app just follows it.
A Strategy makes an algorithm interchangeable at runtime, so the caller stays the same while the method varies. In modern languages this is often just passing a function rather than a whole class — which is the point: the pattern is the idea, not the ceremony.
- Problem
- A growing
ifladder over variants of one algorithm. - Idea
- The algorithm is a swappable object (or function) behind one interface.
- Example
A checkout that takes a
PricingStrategy: regular, member, or holiday-sale.- Cost
- A Strategy for one algorithm that never varies is dead weight.
- When to use
- Two or more variants, chosen at runtime.
- Related
- Same shape as State. In modern code, often just a function.
Observer — subscribe, and get told when it changes
A newsletter — you subscribe once, and every new issue comes to you. The publisher doesn't phone each reader; it just sends to the list.
With an Observer, subscribers register with a subject and get notified when it changes — without the subject knowing who they are. It's the backbone of event-driven and reactive code.
- Problem
An object must tell many others about a change without knowing them by name.
- Idea
- A list of subscribers +
notify()on every change. - Example
A spreadsheet cell refreshing every chart that depends on it; UI frameworks reacting to state; pub/sub everywhere.
- Cost
Notification chains are hard to trace; a forgotten subscription lives forever.
- When to use
- Several independent parts react to one change.
- Related
The basis of event-driven code — the same as Event-driven architecture, inside one program.
Command — wrap a request as an object
A restaurant order ticket — the request "table 5, two coffees" becomes a slip you can queue, reorder, log, and even tear up.
A Command turns an action into a standalone object, so you can queue it, log it, schedule it, or undo it. It's how an action becomes something you can store and replay.
- Problem
- An action needs to be delayed, repeated, logged, or undone.
- Idea
- Pack the action into an object with everything needed to run it.
- Example
Every edit in an editor is a command — hence undo/redo and macros. A job queue is commands waiting their turn.
- Cost
- An object per action; undo has to be thought through for each command.
- When to use
- Undo/redo, queues, macros, an action log.
- Related
- Often paired with Memento for undo.
Chain of Responsibility — pass it along until someone handles it
Customer support tiers — the front desk tries, escalates to a specialist, then to a manager, until someone can actually solve it.
With a Chain of Responsibility, a request travels along a chain of handlers; each either deals with it or passes it on. It decouples the sender from whoever ends up doing the work.
- Problem
- The sender shouldn't know who exactly will handle the request.
- Idea
- A chain of handlers: each does its part or passes it on.
- Example
Web middleware: auth, then logging, then rate-limiting, then the route itself.
- Cost
- The order of links matters; a request can run the whole chain unhandled.
- When to use
- Several independent checks or steps before the main work.
- Related
- On the web you almost always meet it as middleware.
Good behavioural patterns let two pieces cooperate without either one hard-wiring the other in.
The second half of the behavioural patterns: how an object's behaviour changes with its state, how you step through collections, and how you fix a skeleton while leaving one step open.
State — behaviour that changes with the mode you're in
A traffic light — green, yellow, red — where each colour decides what happens now and which colour comes next. Same light, different behaviour per state.
The State pattern lets an object change its behaviour as its internal state changes. A tangle of if and switch becomes clear states and transitions — a small state machine. It turns a mess of flags into a tidy little machine.
- Problem
Behaviour depends on a mode, and the code fills up with flags and
switch.- Idea
- Each state is its own object with its own rules and transitions.
- Example
An order that behaves differently as
pending,paid,shippedorcancelled; each state knows only its own rules and what it can become.- Cost
- Lots of small classes; for two states a plain
ifis enough. - When to use
- Many states, and the transitions between them matter.
- Related
Same shape as Strategy, but the object switches state itself as it lives.
Iterator — step through a collection without seeing its insides
A TV remote's next and previous — you move through channels without knowing how they're stored.
An Iterator gives a uniform way to walk a collection without exposing how it's built — array, tree, or linked list. This one is so useful the language usually has it built in — for..of, generators, __iter__. It's the clearest sign a pattern can graduate into a language feature.
- Problem
- Traversal code depends on how the collection is built.
- Idea
- One way to get "the next element", whatever is inside.
- Example
for (item of collection)works the same over a list or a custom structure.- Cost
- Close to zero — it's usually built into the language already.
- When to use
- Always — but through the built-in tools, not by hand.
- Related
- Walks the trees built with Composite.
Template Method — a fixed recipe with one blank to fill
A recipe that's identical every time — except "add your choice of spice" at step four. The skeleton is fixed; one step is yours.
A Template Method defines the skeleton of an operation in a base class and lets specific steps be overridden without changing the overall shape. Useful when many flows share a shape but differ in a spot or two.
- Problem
- Several flows of the same shape copy each other almost entirely.
- Idea
The skeleton lives in a base class; the varying steps live in subclasses.
- Example
An importer that opens, reads, parses (you fill this in), and saves; CSV and JSON importers supply only the parse step.
- Cost
- It relies on inheritance; the skeleton is hard to change later.
- When to use
- The shape is shared, the differences sit in one or two spots.
- Related
Strategy solves a similar problem with composition instead of inheritance.
Mediator, Visitor, Memento — the rest, in one breath
A toolbox has tools you reach for monthly, not daily — but you should still know they exist.
A handful more earn their place occasionally. Mediator — a control tower so objects talk through one hub instead of a tangle of direct links. Visitor — add new operations to a structure without editing its classes. Memento — capture an object's state so you can restore it later. Know the names; reach for them only when the exact problem appears.
- What it is
One hub objects talk through instead of linking to each other directly.
- Picture
- A control tower: planes talk to it, not to each other.
- When to use
- Direct links between objects have become too many.
- What it is
- A new operation over a structure, moved into its own object.
- Example
Exporting every shape in a document — without editing the shape classes.
- When to use
- The structure is stable, but operations on it keep multiplying.
- What it is
- A saved state of an object you can go back to.
- Example
- Save points in a game, undo snapshots in an editor.
- Related
- Together with Command it gives you undo.
When a pattern becomes a language keyword, stop writing the pattern and use the keyword.
The catalogue is decades of hard-won wisdom — and also a product of its time. Use it like a senior engineer, not a checklist.
Language features — many patterns are now built in
We used to give directions by landmarks; now the phone navigates. The skill didn't vanish — it got absorbed into the tool.
Iterator is for..of. Strategy is often a function passed in. Decorator and Observer are first-class in modern frameworks. When the language hands you the shape for free, writing the full pattern by hand is just ceremony (boilerplate). The idea still matters; the boilerplate usually doesn't.
Pattern-itis — a real disease
A cook who empties the whole spice rack into one dish doesn't get a richer meal — they get an inedible one.
Pattern-itis is the classic over-engineering smell: reaching for patterns to look sophisticated. And it's worse now — an AI assistant will happily generate a "Multi-Level Abstract Factory" for what should be three lines. Simpler code is almost always the more senior choice.
- What it is
- Patterns for their own sake, not to relieve a pain.
- Symptoms
An abstract factory for one product, a Strategy for one algorithm that never varies, five layers of indirection around an
if.- Why it's worse now
- AI assistants generate these structures eagerly and fast.
- Cure
- Simplest code first; a pattern only once the pain shows up.
Patterns are a vocabulary, not a law
Knowing many words doesn't make a good writer. Knowing which word — and when to stay silent — does.
The real value of the catalogue is shared language: "let's put a Facade here" lands instantly with anyone who knows the term, and that is worth a lot on a team. But the goal is always the simplest code that solves the problem. The pattern is a means; naming one is never the achievement.
Learn all the patterns so you can recognise them. Use as few as you can get away with.
Patterns are answers. The skill is matching them to a real question — and knowing when no pattern is the right answer.
Let the pattern emerge from the pain
You don't pick a wrench before you've found the bolt. You see the problem, then reach for the tool that fits it.
Good pattern use is usually a refactoring, not a starting blueprint: you write the simple thing, feel a specific pain — this if ladder keeps growing, this class knows too much about how it's built — and then the pattern that relieves it is obvious. Forcing patterns up front is how you build cathedrals nobody asked for.
Name it only when the name helps
You don't say "I performed a give-and-go" in casual chat. But on the pitch, with teammates, the word saves a whole sentence.
A pattern's payoff is communication and flexibility. If naming it makes the code clearer to the next person, use the name out loud — in a class name, a comment, a design chat. If the indirection buys nothing, the plainest code wins, pattern or not.
Patterns are connected
Words in a language don't live alone: they have synonyms, pairs and relatives.
Adapter, Decorator and Proxy are one shape: a wrapper around an object, with different goals. Strategy and State are alike in shape. Command and Memento together give you undo. Abstract Factory is built from Factory. Composite is walked with Iterator. Observer is the backbone of event-driven code.
- What recurring problem does it solve? Say it in a sentence.
- Do I have that problem now, or am I guessing at the future?
- Would a plain function or object do? Try that first.
- Does my language already give me this for free?
- Will naming it make the code clearer to the next person — or just fancier?
- Am I refactoring toward it, or forcing it in up front?
- You have a factory that builds exactly one thing.
- A Strategy with a single strategy that never changes.
- More interfaces and indirection than actual behaviour.
- You added the pattern to look senior, not to solve a pain.
- A new reader needs a UML diagram to follow three lines of logic.
- The pattern removed an
if/switchladder that kept growing. - You can swap an implementation without touching the callers.
- A teammate recognised the shape from its name immediately.
- The indirection earns its keep — you actually use the flexibility.
- The code is simpler with the pattern than without it, not just cleverer.
Cheat sheet: all 20 patterns and the key ideas
Foundations
- Design Pattern
A named solution to a recurring problem in code. Vocabulary, not a library.
- Gang of FourGoF
The authors of Design Patterns, who catalogued 23 patterns.
- Indirection
A layer between you and the thing. The cost of every pattern.
- Pattern-itisover-engineering
Patterns for show, not for pain. Simple code almost always wins.
Creational
- FactoryFactory Method
Ask for an object by name; the factory picks the class.
- Abstract Factory
A factory for a whole matching family of objects.
- Builder
A complex object step by step, then
build().- Singleton
Exactly one instance for everyone. Careful: global state.
- Prototype
- Clone a ready object and tweak it.
Structural
- Adapter
A converter: one interface looks like another.
- Decorator
A wrapper adds behaviour; the interface stays the same.
- Facade
- One simple door into a complex subsystem.
- Proxy
Stands in front of an object and controls access.
- Composite
- A leaf and a tree share one interface.
Behavioural: talking
- Strategy
A swappable algorithm; often just a function.
- Observer
- Subscribers get told about changes.
- Command
- An action as an object: queue, log, undo.
- Chain of Responsibilitymiddleware
Handlers in a chain; on the web, middleware.
Behavioural: state and steps
- State
- Each state has its own rules and transitions.
- Iterator
Walk a collection without looking inside. Usually
for..of.- Template Method
The skeleton is fixed; one step is yours.
- Mediator
- Everyone talks through one hub.
- Visitor
- A new operation without editing the classes.
- Memento
- Save a state and come back to it.
The best use of a design pattern is the one a reader never notices — because it made the code feel obvious.