Category
Behavioral Patterns
Patterns that assign responsibilities and route requests between objects, so behavior can change without rewriting the code that triggers it.
What these patterns solve
Behavioral patterns are about who does what and who tells whom. They turn requests into objects, let behavior vary by situation, decouple senders from receivers and walk structures without exposing them. Many of them exist to replace a growing conditional or a tangle of direct calls.
Several of these patterns are a function value in disguise. Check that first-class functions, closures, iterators or your platform's events don't already cover the need.
Members
- Chain of Responsibility: passes a request along a list of handlers until one handles it, as in HTTP middleware.
- Command: wraps an action and its arguments in an object so it can be queued, logged, retried or undone.
- Iterator: walks a collection without exposing how it is stored.
- Mediator: routes communication between many components through one coordinator instead of letting them call each other.
- Memento: captures an object's state as an opaque snapshot so it can be restored later without breaking encapsulation.
- Observer: lets objects subscribe to events from another object and get notified when they occur.
- State: moves state-specific behavior into separate objects so an object changes behavior when its state changes.
- Strategy: puts interchangeable algorithms behind one interface and lets the caller pick one at runtime.
- Template Method: fixes an algorithm's skeleton in a base class and lets subclasses fill in specific steps.
- Visitor: adds operations over a fixed set of node types without editing those types.
How to choose within this category
- A
switchpicks between algorithms: Strategy. A function parameter is often enough. - A
switchon a status field appears in many methods, and the status changes over time: State. For a handful of states, a transition table or a discriminated union may be clearer. - The steps are fixed and only a few vary: Template Method. Passing the varying steps as functions avoids inheritance.
- An action must be queued, retried, logged or undone: Command. Undo also needs Memento or an inverse operation.
- Several handlers might process a request, in order: Chain of Responsibility.
- One change must notify an unknown number of listeners: Observer. Use your platform's event emitter, channels or signals before writing your own.
- Many components call each other directly: Mediator.
- You need many operations over a stable set of types: Visitor. Exhaustive pattern matching over a sealed or union type replaces it in TypeScript, Rust, Kotlin and Java 21+. See Visitor and double dispatch.
- You need to traverse a custom structure: implement your language's iteration protocol (
Symbol.iterator,__iter__,Iterable, range-over-func in Go) rather than a separate Iterator class.
Prefer no pattern when
- There are two branches and no third in sight. Keep the
if. - The behavior is one stateless function. Pass the function.
- Only one listener or handler will ever exist. Call it directly.
See also
- Creational PatternsPatterns that control how objects get built, so callers depend on what they need rather than on which concrete class supplies it.
- Structural PatternsPatterns that combine objects and classes into larger structures while keeping each part replaceable and its interface small.
- Choosing a PatternA decision guide that maps concrete code symptoms to the pattern that fixes them, and tells you when plain code beats any pattern.
- Visitor and Double DispatchWhy overloading alone cannot pick a method by an argument's runtime type, how Visitor uses double dispatch to fix it, and when pattern matching replaces it.
Original writing and examples. Topic coverage follows Refactoring.Guru, which explains this topic with its own illustrations.