In one line. A design pattern is a named, proven solution to a problem that keeps coming up — a shared vocabulary that lets one engineer say “let’s use a Strategy here” and another instantly know what they mean.
Patterns aren’t code you download. They’re descriptions of a design that you adapt to your language and problem. The catalog comes from the 1994 book Design Patterns by the “Gang of Four” (GoF), which cataloged 23 of them. That catalog is the backbone of this guide — but we read it through a Go lens, because Go changes the answers.
Why patterns are worth your time
Shared vocabulary
”Wrap it in a Decorator” compresses a paragraph of explanation into two words on a code review.
Tried-and-tested
Each pattern encodes trade-offs people already learned the hard way, so you skip some of the mistakes.
Design for change
Most patterns exist to isolate the part of a system most likely to change behind a stable interface.
The three families
The 23 GoF patterns split into three groups by what kind of problem they solve.
graph TD A["Design Patterns (GoF)"] --> C["Creational<br/>how objects are made"] A --> S["Structural<br/>how objects are composed"] A --> B["Behavioral<br/>how objects interact"] C --> C1["Singleton · Factory Method<br/>Abstract Factory · Builder · Prototype"] S --> S1["Adapter · Bridge · Composite · Decorator<br/>Facade · Flyweight · Proxy"] B --> B1["Strategy · Observer · Command · State<br/>Iterator · Template Method · and more"]
🎯 A quick way to remember them
Creational = the birth of objects. Structural = the shape objects form together. Behavioral = the conversation between objects.
Why Go is different
Most pattern tutorials are written for Java or C++. Go deliberately omits features those languages lean on — and that changes everything.
| Java / C++ relies on… | Go gives you instead… | Effect on patterns |
|---|---|---|
| Class inheritance | Struct embedding (composition) | Template Method, Decorator become composition |
Explicit implements | Implicit, small interfaces | Adapter & Strategy get trivial |
| Objects everywhere | First-class functions | Strategy/Command can be a func value |
| Threads + locks | Goroutines + channels | Observer/Pub-Sub become channel-native |
| Constructors | Plain NewX() functions | Factory Method is just a function |
🐹 The Go proverbs that matter here
“Accept interfaces, return structs.” · “The bigger the interface, the weaker the abstraction.” · “Don’t communicate by sharing memory; share memory by communicating.” Each one quietly rewrites a classic pattern.
So in this guide, every pattern page asks two questions: what’s the classic shape? and what does it actually look like in idiomatic Go? Sometimes the answer is “a one-line function.” That’s a feature, not a disappointment.
The four pillars behind Go’s approach
- Interfaces are implicit. A type satisfies an interface just by having the methods — no
implementskeyword. This makes Adapter, Strategy and Dependency Injection nearly free. - Embedding, not inheritance. Put a struct inside another and its methods are promoted. You get reuse without a class hierarchy.
- Functions are values. You can pass behavior directly, so many “make an object to hold one method” patterns collapse.
- Concurrency is built in. Goroutines and channels turn Observer, Pipeline and Pub/Sub into language-level idioms.
The design principles behind every pattern
Patterns are applications of a smaller set of principles that run through the whole catalog. Learn these nine and most patterns become obvious — they’re just principles assembled for a specific problem:
| Principle | In a sentence |
|---|---|
| Encapsulate what varies | Separate the changing part from the stable part |
| Favor composition over inheritance | HAS-A beats IS-A for flexibility |
| Program to interfaces, not implementations | Depend on abstractions, not concrete types |
| Strive for loose coupling | Minimize what interacting objects know of each other |
| Open/Closed | Open for extension, closed for modification |
| Dependency Inversion | High- and low-level code both depend on abstractions |
| Least Knowledge (Demeter) | Talk only to your immediate friends |
| Hollywood Principle | ”Don’t call us, we’ll call you” — the framework drives |
| Single Responsibility | One class/type, one reason to change |
Go’s design pushes you toward several of these by default — composition (embedding), program-to-interfaces (implicit interfaces), loose coupling (small interfaces) — which is exactly why so many patterns shrink in Go.
How to read a pattern page
Every pattern in this guide follows the same structure, so you always know where to look:
Intent & analogy
One-line purpose plus a real-world story to anchor it in memory.
Problem & structure
The pain it removes, then a UML diagram of the moving parts.
Idiomatic Go
Runnable Go code — the Go-native form, not a Java translation.
Trade-offs & quiz
When to use it, when not to, where the stdlib uses it, and a self-check.
✅ Mark pages as 'learned'
Use the Mark as learned button on every pattern page to track your journey. Your progress bars on the home page fill up as you go — it’s all saved in your browser.
Ready? The most natural place to begin is the very first creational pattern.
Related patterns
Ensure a type has only one instance, and provide a single, well-defined point of access to it.
behavioralStrategyDefine a family of interchangeable algorithms, encapsulate each one, and select which to use at runtime.
stdlibPatterns in the Go Standard LibraryA tour of the classic design patterns hiding in plain sight across Go's standard library.
Check your understanding
Score: 0 / 51. What is a design pattern, most precisely?
A pattern is a description of a solution — a shared vocabulary — not code you import. You implement it yourself, shaped by your language.
2. Why do several classic patterns shrink or vanish in Go?
Many GoF patterns work around the absence of features Go has built in. Strategy is often just a function value; Iterator is range; Observer leans on channels.
3. Which statement reflects idiomatic Go best?
Go has no inheritance. It composes behavior with struct embedding and satisfies small, implicit interfaces — accept interfaces, return structs.
4. Which single principle underlies nearly every design pattern?
Almost every pattern isolates the volatile part of a design behind a stable boundary: Strategy isolates an algorithm, Decorator isolated added behavior, Factory isolates construction. 'Encapsulate what varies' is the seed most patterns grow from.
5. A teammate wraps everything in patterns 'to be flexible.' What does the book warn?
Patterns earn their keep against actual change and complexity. Forcing them speculatively ('pattern fever') adds layers, names, and indirection with no payoff — the simplest thing that works, especially in Go, often beats a formal pattern.
Comments
Sign in with GitHub to join the discussion.