Discover the Mediator Design Pattern, its benefits, and when to use it for cleaner, maintainable code in complex systems.
TL;DR: The Mediator pattern acts as a central communication hub between objects in your code, like an air traffic control tower. Instead of objects talking directly to each other, they communicate through the mediator.
Here's what you need to know:
Feature
Without Mediator
With Mediator
Communication
Objects talk directly
Objects talk through mediator
Complexity
Many connections
One central hub
Changes
Affect many objects
Only affect mediator
Maintenance
Hard to modify
Easy to update
Testing
Complex
Simple
Perfect for:
- Chat applications
- Complex UIs
- Business systems
- Message routing
- Event handling
But skip it if:
- You have a small system
- Speed is critical
- Only a few objects interact
- Direct connections work fine
Think of it this way: In a chat app, users don't message each other directly - they send messages to a server (mediator) that handles delivery. Same idea in code - the mediator manages all communication between components.
The pattern shines in big systems but can be overkill for simple projects. You'll trade a tiny bit of speed for much cleaner, more maintainable code.
Related video from YouTube
What is the Mediator Pattern?
The Mediator Pattern puts a central object in charge of all communication. Objects don't need to know about each other - they just talk to the mediator.
Here's what changes when you use a mediator:
Without Mediator
With Mediator
Objects hold direct references to each other
Objects only reference the mediator
Changes to one object affect many others
Changes only affect the mediator
Complex web of connections
Simple hub-and-spoke model
Hard to add/remove objects
Easy to add/remove objects
The Mediator Pattern comes from the famous "Gang of Four" book on design patterns. It's all about making object communication simpler and more organized.
Why Use It?
The Mediator Pattern fixes four big problems:
- Too Many Connections: Without a mediator, adding new objects creates a mess of connections
- Tight Coupling: Objects become too dependent on each other
- Brittle Code: Changes to one object can break others
- Limited Reuse: Objects with direct connections don't work well in other projects
Think about a chat app:
Without a mediator, each user would need connections to EVERY other user. But with a mediator? Users just connect to the chat server. Adding or removing users becomes super simple.
Or look at air traffic control:
The control tower (mediator) manages ALL communication between planes. Planes don't track each other - they just follow the tower's instructions. It's the same idea in code: the ATCCentral class handles everything, keeping the system organized and efficient.
How the Mediator Pattern Works
The Mediator Pattern is like a traffic control tower at an airport. Instead of planes talking directly to each other, they communicate through the tower.
Main Concepts
Objects don't communicate directly - they send messages through a mediator. It's similar to how a chat app works:
- You don't DM other users directly
- You send messages to the server
- The server handles message delivery
- Users only need to know how to talk to the server
Pattern Layout
Here's what makes up the pattern:
Component
Role
Example
Mediator Interface
Sets communication rules
notify() method
Concrete Mediator
Handles the coordination
Chat server
Colleague Classes
Objects that need to talk
Chat users, UI elements
Main Pattern Components
Let's look at a washing machine to see this in action:
Component
What It Does
Example
Mediator
Controls everything
Control unit
Concrete Mediator
Runs specific programs
Cotton wash cycle
Colleague Classes
Individual parts
Water valve, heater, buttons
Here's how it works:
- You press a button
- The control unit gets the signal
- It tells the water valve to open
- It signals the heater to warm up
The beauty of this setup? You can:
- Add new parts without touching the old ones
- Change how parts work together by updating the mediator
- Test each part on its own
Think of the mediator as the brain of the operation. It keeps everything organized by being the one point all messages flow through.
Main Benefits
The Mediator Pattern makes your code better by changing how objects talk to each other. Here's what it does:
Fewer Moving Parts
Look at the difference it makes:
Before Mediator
With Mediator
Objects need to know each other
Objects just know the mediator
Many objects connected to many others
Objects only connect to mediator
Adding objects is a pain
Adding objects is simple
One change hits many objects
Changes only hit the mediator
One Control Point
Think of the mediator as air traffic control for your code. It:
- Handles ALL object communication
- Shows you who's talking to who
- Makes finding bugs easier
- Lets you change how things work fast
Better Communication
The mediator makes everything clearer:
What It Does
How It Works
Message Handling
Everything goes through one place
Object Setup
Objects don't care about other objects
Problem Fixing
Catch all issues in one spot
Testing
Check each piece by itself
Quick Changes
Want to update your code? The mediator makes it simple:
- Fix ONE thing instead of many
- Add new stuff without breaking old code
- Change rules in one place
- Test with less worry
Mix and Match Code
Your code pieces work better together:
What You Get
How It Helps
Movable Parts
UI stuff works anywhere
Stand-Alone Pieces
Objects work with any mediator
Easy Combos
Put pieces together how you want
Better Testing
Test without extra baggage
Here's a real example: In a chat app, the chat room is the mediator. It handles ALL messages between users. Nobody needs to know about anyone else - they just talk to the room. Want to add new features? Just update the room's code. Simple.
sbb-itb-bfaad5b
How to Implement the Pattern
Here's how to add a Mediator Pattern to your code:
Creating the Interface
First, build your mediator interface:
public interface IChatMediator {
void SendMessage(string msg, User user);
void RegisterUser(User user);
}
The interface needs two main methods: one to send messages and another to add users.
Building Mediators
Next, create your concrete mediator:
public class ChatMediatorImpl : IChatMediator {
private List<User> users = new List<User>();
public void RegisterUser(User user) {
users.Add(user);
user.Mediator = this;
}
public void SendMessage(string message, User user) {
foreach (User u in users) {
if (u != user) {
u.Receive(message);
}
}
}
}
Making Colleague Classes
Your colleague classes need:
Part
What It Does
Base Class
Holds mediator reference
Methods
Handles messages
Properties
Stores user data
Setting Up Communications
Here's how to connect everything:
var mediator = new ChatMediatorImpl();
var user1 = new ConcreteUser("User1");
var user2 = new ConcreteUser("User2");
mediator.RegisterUser(user1);
mediator.RegisterUser(user2);
Implementation Tips
Want to keep your code clean? Follow these tips:
Do This
Because
Small mediators
Easier to maintain
Use interfaces
Better for testing
No direct links
Keeps code flexible
Test separately
Catches bugs early
Here's how to use MediatR in .NET:
services.AddMediatR(typeof(Program));
services.AddTransient<UserService>();
This pattern keeps your code organized by letting the mediator handle all communication between components.
Where to Use It
The Mediator Pattern shines in situations where multiple components need to talk to each other. Let's look at where it works best:
Business Software
In big business apps, the Mediator Pattern handles communication between different parts:
Component
What It Manages
User Interfaces
Screen updates and user input
Business Logic
Data processing and rules
Databases
Data storage and retrieval
External Services
API calls and responses
UI Design
It keeps screen elements organized without messy connections:
UI Element
What It Does
Forms
Checks and sends input
Buttons
Handles clicks and states
Panels
Updates content
Modals
Shows/hides and moves data
Traffic Control
Air traffic systems use it to keep planes safe:
Function
What It Does
Flight Tracking
Watches where planes are
Landing Control
Says who can land when
Route Planning
Sets flight paths
Emergency Response
Handles urgent issues
Message Systems
Chat apps use the pattern to move messages around:
Feature
What It Does
Message Routing
Sends messages to right users
User Status
Shows who's online
Group Chats
Handles multiple users
Message History
Keeps chat records
Event Management
It helps manage system events:
Event Type
What It Does
System Alerts
Sends notifications
User Actions
Handles responses
State Changes
Updates components
Error Handling
Deals with errors
The pattern works when you need to:
- Keep objects from talking directly to each other
- Change how objects work together
- Handle complex message routing
- Control communication between many parts
Pros and Cons
Let's break down what you'll get (and what you'll give up) when using the mediator pattern:
The Good Stuff
What You Get
How It Helps
No Direct Links
Components only talk through the mediator - no messy connections
Easy Testing
Test each piece on its own using the mediator
Simple Updates
Fix one part without breaking others
Room to Grow
Add new components without touching old code
The Not-So-Good Stuff
What to Watch For
Why It Matters
One Weak Spot
If the mediator breaks, everything breaks
Big Middle-Man
Your mediator can turn into a monster
More Setup Work
Takes time to get everything connected right
Extra Learning
Every component needs to know the mediator's rules
What About Speed?
Looking At
What Happens
Getting Messages Across
Takes longer than direct connections
Moving Things Around
Mediator needs time to sort messages
Computer Resources
Uses more memory than simple connections
Overall Speed
Slightly slower, but you'll barely notice
Extra Work You'll Do
Task
What's Involved
Setting Up Rules
Creating clear ways for things to talk
Fixing Old Code
Making existing parts work with mediator
Writing It Down
Explaining how the mediator works
More Testing
Making sure the mediator handles everything right
Here's the bottom line: The mediator pattern shines in big projects where you need to keep things organized. Sure, it's a bit slower and needs more setup time. But in large systems? The clean organization is worth the small speed bump.
But if you're building something small with just a few parts talking to each other? Skip it - you'll just make extra work for yourself.
Summary
The Mediator pattern is like a traffic cop for your code - it directs communication between objects through one central point. Let's break down what makes it tick:
Core Benefits
What It Does
How It Works
Controls Messages
Acts as a central hub for all object communication
Keeps Objects Apart
Removes direct connections between components
Makes Systems Cleaner
Turns messy connections into organized flows
Sets Clear Structure
Uses mediator and colleague classes to organize code
Think of it like an air traffic control tower. Planes don't talk directly to each other - they all communicate through the tower. This keeps things organized and safe.
When It Shines (And When It Doesn't)
Use It When
Skip It When
Many objects need to communicate
Just a few objects interact
Communication paths get messy
Direct connections work fine
You want central control
Speed is critical
Testing needs to be simple
System is small and basic
What You'll Get
Area
Result
Code Structure
Cleaner, easier to read
Making Changes
Less risky updates
Speed
Small performance cost
Upkeep
More mediator work, simpler components
The pattern works great for:
- Chat apps with central servers
- UI parts that work together
- IoT devices sharing data
- Complex business systems
"The Mediator pattern cuts down object coupling, makes communication smoother, and helps maintain complex systems." - Carlos Caballero, Author
But here's the thing: don't use it just because you can. For small projects, it's often overkill. But when your system gets big and complex? That's when the Mediator pattern really pays off.
FAQs
Question
Answer
What's different about Mediator vs Observer patterns?
Mediator uses a central hub for two-way communication between components. Observer sets up one-way notifications from a subject to its watchers. Mediator connects senders and receivers indirectly, while Observer lets multiple watchers track changes.
When should I pick the Mediator pattern?
Pick it when you need a traffic cop for your objects. It works great in big systems where lots of parts need to talk to each other. You'll want central control over who talks to who.
What does the Mediator pattern do?
Think of it as an air traffic controller. It manages all communication between objects in your system. No object needs to know about other objects - they just talk through the mediator.
Benefits
Drawbacks
Objects don't need to know each other
Mediator can get bloated
Makes updates easier
Takes time to set up
Cleaner communication
Might run a bit slower
Better testing
Need smart planning
"The Mediator pattern cuts object dependencies. It's like giving your code room to breathe." - Shahar Shokrani, Author
Here's what to remember:
- Make your mediator stick to passing messages
- Keep business logic OUT of the mediator
- Watch that your mediator doesn't turn into a monster
- Check ALL your message paths
The pattern works best in:
- Chat systems
- Connected UI parts
- Complex systems
- Message routing