
Seeing the Forest, Not Just the Trees: Design Pattern Relationships
Have you ever learned individual design patterns but struggled to understand how they relate to each other? That was exactly my problem.
When reading Alexander Shvets’ excellent book “Dive Into Design Patterns,” I was particularly drawn to the “Relations with Other Patterns” section. This unique feature helps bridge the gap between knowing individual patterns and truly understanding their ecosystem.
I believe the journey of pattern mastery has three levels:
- What is this pattern? (Basic understanding)
- Why use this pattern? (Practical application)
- How does this pattern compare to similar ones? (Deep comprehension)
While Shvets provides some pattern relationships, I felt there was room for a deeper exploration specifically among behavioral patterns. This post is my attempt to map the connections, similarities, and differences between these patterns to help fellow developers level up their design pattern knowledge.
This blog post doesn't dive into explanation of each behavioral design pattern. This blog is solely about their similarities, differences and relationships.
Behavioral Design Patterns
Chain of Responsibility: lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.Command: Turns a request into a stand-alone object that contains all information about the request. This transformation lets you parameterize methods with different requests, delay or queue a request’s execution, and support undoable operations.Mediator: Lets you reduce chaotic dependencies between objects. The pattern restricts direct communications between the objects and forces them to collaborate only via a mediator object.Observer: Lets you define a subscription mechanism to notify multiple objects about any events that happen to the object they’re observing.Iterator: Lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).Memento: Lets you save and restore the previous state of an object without revealing the details of its implementation.State: Lets an object alter its behavior when its internal state changes. It appears as if the object changed its class.Strategy: Lets you define a family of algorithms, put each of them into a separate class, and make their objects interchangeable.Template Method: Defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.Visitor: Lets you separate algorithms from the objects on which they operate.
Similarities
All behavioral design patterns focus on communication between objects. They provide elegant solutions to common programming challenges related to object interaction.
Most behavioral patterns provide ways to change behavior without altering existing code, following the Open/Closed Principle.
Most patterns aim to reduce dependencies between objects, promoting loose coupling for more maintainable and flexible code.
The Pattern Relationships Map
Before diving into specific comparisons, here’s a high-level view of how these patterns relate to each other:
graph TD
Command -->|can implement| ChainOfResp[Chain of Responsibility]
Command -->|works with| Memento
Command -->|simpler version of| Visitor
Iterator -->|used by| Visitor
Iterator -->|works with| Memento
Mediator -->|can use| Observer
Strategy -->|specializes into| State
Template -->|alternative to| Strategy
class Command,ChainOfResp,Memento,Mediator,Observer,Iterator,Visitor,State,Strategy,Template pattern
Command
Command vs. Strategy
Command decouples the object invoking an operation from the one performing it.
Strategy provides interchangeable algorithms.
Think of it this way:
Commandsays: “I’ll handle what needs to be done and when”Strategysays: “I’ll handle how something gets done”
graph TD
subgraph Command Pattern
Invoker1[Invoker] -->|executes| Command1[Command]
Command1 -->|calls| Receiver1[Receiver]
end
subgraph Strategy Pattern
Context -->|uses| Strategy[Strategy Interface]
Strategy -->|implemented by| ConcreteA[Strategy A]
Strategy -->|implemented by| ConcreteB[Strategy B]
end
class Command1,Strategy main
Command vs. Memento
Command can work together with Memento for implementing “undo” functionality.
Commands handle operations while Mementos save the state before command execution.
It’s like having both:
- A to-do list (commands)
- Snapshots of your room (mementos) before each task
Command vs. Visitor
Visitor can be viewed as a powerful version of Command.
Command does a single operation. So if you want to add new features (which means new methods) to multiple classes, you need to add a new command for each class.
Visitor does multiple operations since it traverses over multiple objects. So if you want to add new features to multiple classes, you just need to create 1 more Visitor. All classes already have the visit() method in themselves.
Command vs. Chain of Responsibility vs. Observer vs. Mediator
Chain of Responsibility, Command, Mediator, and Observer all address different ways of connecting senders and receivers.
In Chain of Responsibility, single sender sends messages sequentially and unidirectional to single receiver.

In Command, multiple senders send messages unidirectional to a single receiver.

graph TD
Button1[Button] -->|executes| Command1[Command 1]
Button2[Button] -->|executes| Command2[Command 2]
Menu[Menu Item] -->|executes| Command1
Shortcut[Shortcut] -->|executes| Command2
Command1 -->|calls| Receiver[Receiver]
Command2 -->|calls| Receiver
Chain of Responsibility can be implemented with Command. Each handler in Chain of Responsibility can be a command. This is helpful when multiple handlers are needed interchangeably. Like having multiple authentication handlers. each one executes a different authentication command.
In Mediator, multiple objects send messages bidirectional to multiple objects via a central object called Mediator.

graph TD
Component1[Component 1] <-->|communicates via| Mediator
Component2[Component 2] <-->|communicates via| Mediator
Component3[Component 3] <-->|communicates via| Mediator
Component4[Component 4] <-->|communicates via| Mediator
In Observer, single sender sends messages unidirectional to multiple subscribed receivers.

graph TD
Publisher -->|notifies| Subscriber1[Subscriber 1]
Publisher -->|notifies| Subscriber2[Subscriber 2]
Publisher -->|notifies| Subscriber3[Subscriber 3]
Mediator can also be implemented with Observer. The mediator object acts as publisher and components as subscribers.
Strategy
Strategy vs. State
Both are based on composition and delegate work to helper objects.
State can be considered an extension of Strategy (Each State being an Strategy).
Strategy makes objects completely independent and unaware of each other.
But States know each other and transition between each other. You can’t expect a Strategy to change to another Strategy when it is executed.
graph TD
subgraph "Strategy Pattern"
Context1[Context] -->|uses| Strategy[Strategy]
Strategy -->|implemented by| StrategyA[Strategy A]
Strategy -->|implemented by| StrategyB[Strategy B]
end
subgraph "State Pattern"
Context2[Context] -->|has current| State[State]
State -->|implemented by| StateA[State A]
State -->|implemented by| StateB[State B]
StateA -->|transitions to| StateB
StateB -->|transitions to| StateA
end
class Strategy,State main
Strategy vs. Template Method
Both design patterns deal with using an algorithm.
In Template Method there is a single algorithm with multiple abstract and concrete steps. Subclasses of this Template implement their own steps from abstract steps. Template Method uses inheritance.
But In Strategy there are multiple algorithms. These algorithms don’t share anything with each other. We can change the algorithm that we want at runtime via composition.
graph TD
subgraph "Template Method Pattern"
AbstractClass -->|inherits| ConcreteClass1[Concrete Class 1]
AbstractClass -->|inherits| ConcreteClass2[Concrete Class 2]
AbstractClass -->|contains| TemplateMethod[Template Method]
TemplateMethod -->|calls| Step1[Abstract Step 1]
TemplateMethod -->|calls| Step2[Concrete Step]
TemplateMethod -->|calls| Step3[Abstract Step 2]
ConcreteClass1 -->|implements| Step1
ConcreteClass1 -->|implements| Step3
ConcreteClass2 -->|implements| Step1
ConcreteClass2 -->|implements| Step3
end
subgraph "Strategy Pattern"
Context -->|uses| StrategyInterface[Strategy]
StrategyInterface -->|implemented by| StrategyA[Strategy A]
StrategyInterface -->|implemented by| StrategyB[Strategy B]
end
class TemplateMethod,StrategyInterface main
Iterator
Iterator vs. Visitor
They can be used together. In Visitor pattern we need to traverse over multiple different objects. This can be done effectively with Iterator.
A good analogy is:
Iteratoris like a tour guide who knows how to navigate through a museumVisitoris like a photographer who performs an action (taking photos) at each exhibit
Iterator vs. Memento
- You use the Iterator to traverse your collection
- At any point, you can use the Memento to take a “snapshot” of the iterator’s state (current position, traversal path, etc.)
- If you encounter a problem later in the traversal, you can restore the iterator to its previous state using the saved memento
It’s like having:
- A map with directions (Iterator)
- A bookmark that saves your place (Memento)
Observer vs. State
Both involve state changes, but:
- In
Observer, objects are notified when a subject’s state changes - In
State, an object’s behavior changes when its state changes
%%{init: {'flowchart': {'rankSpacing': 100, 'nodeSpacing': 50, 'layoutDirection': 'TB'}}}%%
graph TD
%% First subgraph (appears at the top)
subgraph "Observer Pattern"
Subject -->|notifies| Observer1[Observer 1]
Subject -->|notifies| Observer2[Observer 2]
end
%% Second subgraph (appears below the first)
subgraph "State Pattern"
Context -->|delegates to| State[Current State]
State -->|implemented by| StateA[State A]
State -->|implemented by| StateB[State B]
end
When to Choose Which Pattern
Here’s a quick decision guide:
- Need to pass a request through a series of processing objects? → Chain of Responsibility
- Need to encapsulate a request as an object? → Command
- Need to reduce dependencies between objects? → Mediator
- Need a subscription mechanism? → Observer
- Need to traverse a collection? → Iterator
- Need to capture an object’s state? → Memento
- Need to change an object’s behavior when its state changes? → State
- Need interchangeable algorithms? → Strategy
- Need to define an algorithm skeleton with customizable steps? → Template Method
- Need to add operations to objects without modifying them? → Visitor
References
- Shvets, Alexander. Dive Into Design Patterns. Refactoring.Guru, 2019.
- Open/Closed Principle