Named, tested ways out of the problems object-oriented code keeps running into.
A design pattern is a reusable solution to a problem that keeps coming up in your code. Instead of copying and pasting code, it allows you to stay flexible and quickly implement new features as your project evolves. The patterns here come from the iconic Gang of Four, who cataloged them in 1994 and sorted them into three families: creational, structural, and behavioral.
There is no right or wrong order to learn design patterns in, so the order doesn't really matter. However, if you start at a certain section, I urge you to explore other design patterns in the same section so you learn the fundamental differences between them. I've also added fun exercises for each design pattern so you can actually practice implementing them!
Creational patterns deal with how objects get made. Instead of spamming constructor calls and setup logic all over your code, they keep object creation in one flexible place. There are five patterns that live here, from the everyday Factory Method to the goat Singleton.
Adding a new product type shouldn't mean editing every place that builds one. Subclasses decide what gets created.
Keeps a whole family consistent: ask for the dark theme and every button, menu, and dialog comes back matching.
A constructor with nine arguments is a trap. Build the object step by step, using only the steps you need.
When setup is expensive or hidden, don't rebuild. Clone a working example and adjust the copy.
One instance, guaranteed, reachable from anywhere. The most famous pattern, and the most abused one.
Structural patterns are about how objects fit together to build something bigger. The goal is to create flexible systems out of smaller parts. There are seven patterns here, and they all have their reasons to exist. I would spend extra time thinking about how and why some of these should be used over others in certain situations.
Your code expects one interface and the library speaks another. A thin wrapper translates so neither has to change.
Three shapes times four renderers shouldn't cost twelve classes. Split the two dimensions and they vary independently.
A file and a folder of a thousand files answer the same call. One thing and a group of things, treated identically.
Stack behaviors at runtime instead of multiplying subclasses. Wrap the object, add the feature, repeat.
One simple call in front of thirty tangled ones. Callers get a clean entry point and the subsystem keeps its mess private.
A million characters on screen, but only a handful of fonts. Share what repeats and memory stops exploding.
A stand-in with the same interface as the real thing, free to lazy-load, cache, or guard before passing the call through.
Behavioral patterns are the largest family. There are ten patterns here in total. They handle how objects talk to each other and split up the work, so the pieces can stay flexible instead of hardcoded together.
Nobody has to know who will handle the request. Each handler either takes it or passes it down the line.
Once a request is an object, you can queue it, log it, and reverse it. Every undo stack is built on this.
Loop over a tree, a list, or a graph with the same code. The collection keeps its insides to itself.
Ten objects talking directly means 45 connections. Route everything through one hub and they stop knowing each other.
Snapshots an object's private state without exposing it. Undo works because someone saved one of these.
One change triggers many reactions without any hard wiring. Subscribers sign up and get notified the moment something happens.
An object that acts like a different object in each state, without a giant switch statement in sight.
Swap the algorithm without touching the code that calls it. Sorting, pricing, and routing rules become plug-ins.
When five algorithms share one outline, write the outline once. Subclasses fill in only the steps that differ.
New operations on a stable family of classes, added without touching a single one of them.