{} The Go Reference

Practice · Guide · Reference

Patterns Cheat-Sheet

A one-page map of every pattern — its intent, the idiomatic Go form, and when to reach for it. Built for revision and interview prep.

Practice Reference ⏱ 4 min read Complete

The whole catalog at a glance. Each row links to the full page; skim to find the right tool, then dive in.

🎯 How to read this

Intent is the one-line purpose. Idiomatic Go is the form you’ll actually write — often lighter than the textbook version, because Go’s interfaces, functions, embedding, and goroutines do a lot of the work.

Creational — how objects get made

PatternIntentIdiomatic Go
SingletonOne instance, one access pointsync.Once; a package-level var
Factory MethodDecide which concrete type to build, behind an interfaceNewX() Iface; a creation method per context
Abstract FactoryCreate a family of related objects that must matchA factory interface with several Create… methods
BuilderConstruct a complex object step by stepFunctional options: New(req, ...Option)
PrototypeCreate new objects by cloning a configured oneExplicit Clone(); slices.Clone / maps.Clone

Structural — how objects compose

PatternIntentIdiomatic Go
AdapterMake an incompatible type fit an expected interfaceA wrapper with the target’s methods (http.HandlerFunc)
BridgeSeparate an abstraction from its implementationHold the implementation as an interface field
CompositeTreat leaves and trees uniformlyAn interface + a node holding []Iface
DecoratorAdd behavior by wrapping, same interfaceEmbed the interface; io wrappers, middleware
FacadeOne simple entry over a complex subsystemA struct holding subsystems, coarse methods
FlyweightShare immutable state across many objectsA cache/interning factory of shared values
ProxyA stand-in that controls accessSame interface, wraps the subject (lazy, cache, ReverseProxy)

Behavioral — how objects collaborate

PatternIntentIdiomatic Go
Chain of ResponsibilityPass a request along handlers until one handles itHTTP middleware func(next) Handler
CommandCapture a request as an object (queue, log, undo)Execute/Undo interface; or a func()
InterpreterEvaluate sentences of a small grammarTree of Eval() nodes (Composite + recursion)
IteratorTraverse a collection without exposing itrange, channels, or iter.Seq (Go 1.23)
MediatorCentralize many-to-many communicationA hub struct colleagues talk to
MementoSnapshot/restore state without breaking encapsulationOpaque struct with unexported fields
ObserverNotify many dependents on changeAn interface list, or channels + goroutines
StateChange behavior with internal stateOne type per state implementing a State interface
StrategySwap interchangeable algorithms at runtimeA func value or small interface (sort.Slice)
Template MethodFixed skeleton, caller fills the stepsInject steps as an interface or func fields
VisitorAdd operations to a stable set of typesAccept/Visit double dispatch, or a type switch

Concurrency — the Go specials

PatternIntentIdiomatic Go
GeneratorLazy/infinite stream from a goroutinefunc(done) <-chan T; producer closes the channel
PipelineStream through channel-connected stagesEach stage owns and closes its output channel
Fan-out / Fan-inParallelize a stage, then merge resultsN workers on one chan; WaitGroup to merge & close
Worker PoolBound concurrency with N workersA jobs channel + a fixed set of workers
SemaphoreCap how many run at onceBuffered chan struct{}; x/sync/semaphore
Context & CancellationPropagate cancel, deadline, request valuesctx first arg; select on ctx.Done()
Or-doneRange a stream that stops cleanly on cancelWrap each receive in a select on done
errgroupConcurrent tasks: wait + first error + cancelerrgroup.WithContext, g.Go, g.SetLimit
Pub/SubBroadcast to dynamic subscribersA broker: mutex-guarded map of channels

Decision shortcuts — “I need to…”

✅ Pick a pattern by what you're trying to do

Patterns that pair or contrast

Half of knowing patterns is telling the look-alikes apart and spotting the natural pairings:

Same shape, different intent (the ones interviews love):

  • Proxy vs Decorator vs Adapter — same/same/different interface; control access / add behavior / change interface.
  • State vs Strategy — drives its own transitions / chosen from outside.
  • Mediator vs Facade vs Observer — many-to-many hub / one-way subsystem door / one-to-many broadcast.
  • Factory Method vs Abstract Factory — one product / a matched family.
  • Template Method vs Strategy — fixed skeleton with holes / the whole algorithm swapped.
  • Composite vs Decorator — a tree of many children / one wrapped component.

Patterns that combine:

  • Command + Memento → undo/redo.
  • Composite + Iterator (or Visitor) → walk and operate on a tree.
  • Abstract Factory is built from Factory Methods, often returning a Singleton.
  • Pipeline + Fan-out/Fan-in + Worker Pool/Semaphore → a bounded concurrent data flow.

Patterns Go quietly reshapes

🐹 Where a 'pattern' becomes a one-liner

  • Strategy → a func value (sort.Slice’s less)
  • Iteratorrange and iter.Seq
  • Singletonsync.Once
  • Observer / Pub-Sub → channels + goroutines
  • Decorator / Chain of Responsibilityio wrappers and HTTP middleware
  • Template Method / Bridge → struct embedding + an interface field
  • Factory → a plain NewX() function

The lesson from Foundations: in Go, many patterns aren’t ceremonies you build — they’re the natural shape the language already nudges you toward.

Check your understanding

Score: 0 / 5

1. Wrapping an http.Handler to add logging, then auth, then gzip — each keeping the same interface — is which pattern?

Same interface in, same interface out, behavior added by wrapping — Decorator. In HTTP form it's a middleware chain (Chain of Responsibility too).

2. You launch a goroutine per request but want at most 5 hitting the API at once. Which pattern?

A counting semaphore caps how many goroutines are in the critical section while you still spawn one per task. A worker pool is the alternative when you have a fixed queue.

3. Letting callers decide how a slice is sorted by passing a comparison function is…

An interchangeable algorithm chosen at runtime — Strategy. In Go it's just a func value, exactly like sort.Slice's `less`.

4. You need exactly one shared config, initialized once, safe under concurrency.

One instance, one access point, initialized once — Singleton, and sync.Once makes the lazy version race-free.

5. State and Strategy have the same shape (delegate behind an interface). What tells them apart?

Structurally identical, different intent. A state machine moves itself between states (states often know each other); a strategy is set by the client and just runs. This 'same shape, different intent' theme recurs: Proxy vs Decorator vs Adapter, Mediator vs Facade.

Comments

Sign in with GitHub to join the discussion.