CacheU
Low Level Design

Mediator Design Pattern

A detailed guide to the Mediator pattern, including centralized communication, chat room example, loose coupling, UML diagrams, real-world use cases, comparisons, and implementations in C++, Java, and Python.

Mediator Design Pattern

The Mediator Design Pattern is a behavioral design pattern that encapsulates how a set of objects interact.

Instead of letting objects communicate directly with each other, the pattern introduces a mediator object that coordinates all interactions.

This helps us:

  • reduce chaotic dependencies
  • avoid tight coupling
  • centralize communication rules
  • simplify object relationships
  • make systems easier to maintain

Introduction: From Chaos to Coordination

Imagine a busy intersection with no traffic lights.

Every car tries to move independently.
Every driver makes their own decision.
The result is chaos.

Now imagine a traffic controller standing in the middle and telling each car when to move.

That is the Mediator pattern.

It replaces a tangled web of direct connections with a central coordinator.


The Problem: A Web of Tangled Connections

When objects communicate directly with each other, the number of relationships grows very fast.

If one object must talk to many others, it needs references to all of them.

If there are n objects, then each object may need up to n - 1 references.

This creates a complicated, brittle design.


Why direct communication becomes a problem

ProblemDescription
Tight couplingObjects depend heavily on each other
Hard maintenanceA change in one object affects many others
Poor scalabilityAdding a new object increases complexity everywhere
Complex dependenciesRelationships become difficult to track
Hard testingEach object is tied to many others

Direct communication diagram

Diagram
flowchart TD A[Object 1] --> B[Object 2] A --> C[Object 3] A --> D[Object 4] B --> A B --> C B --> D C --> A C --> B C --> D D --> A D --> B D --> C

As more objects are added, the network becomes messy.


Core Idea of Mediator

The Mediator pattern introduces a central object called the Mediator.

All other objects become Colleagues.

They no longer talk to each other directly. They talk to the mediator, and the mediator decides how to route or coordinate the interaction.


Formal definition

The Mediator pattern defines an object that encapsulates how a set of objects interact.

It promotes loose coupling by preventing objects from referring to each other directly, and lets them communicate through the mediator instead.


Main participants

RoleMeaningChat Room Example
MediatorCentral coordinatorChat room server
ColleagueParticipating objectUser
Concrete MediatorReal implementation of mediator`ChatMediator`
Concrete ColleagueReal participant object`User`

UML structure

Diagram
classDiagram class Mediator { +sendMessage +register } class ChatMediator { -users +sendMessage +register } class Colleague { +send +receive } class User { -name -mediator +send +receive } Mediator <|.. ChatMediator Colleague <|.. User ChatMediator --> User User --> Mediator

Why Mediator is useful

The mediator centralizes communication logic.

Instead of each object knowing about every other object, each object only knows:

  • the mediator
  • how to send a request to the mediator
  • how to receive a response from the mediator

This dramatically reduces complexity.


Real-world analogy: Chat Room

A chat application is one of the best examples of the Mediator pattern.

Suppose there are many users in a chat room.

Without a mediator:

  • every user must know every other user
  • private messaging becomes messy
  • mute logic becomes scattered
  • group communication becomes hard to manage

With a mediator:

  • each user sends messages to the chat room
  • the chat room decides where to deliver them
  • mute rules, broadcast rules, and routing rules stay in one place

Chat room flow

Diagram
flowchart TD A[User 1] --> B[ChatMediator] C[User 2] --> B D[User 3] --> B B --> A B --> C B --> D

How Mediator simplifies the system

The object relationships become:

  • many colleagues know one mediator
  • mediator knows all colleagues
  • colleagues do not know each other directly

That means:

  • less coupling
  • easier changes
  • simpler object classes

Direct communication vs Mediator communication

AspectDirect CommunicationMediator
Object referencesMany references between objectsEach object knows only mediator
ResponsibilitySpread across many classesCentralized in mediator
MaintenanceHarderEasier
ScalabilityPoorBetter
CouplingTightLoose

Why this improves design

If a new colleague joins the system:

  • direct communication requires changes in many classes
  • mediator communication usually requires only registration with the mediator

If a new communication rule is added:

  • direct communication spreads the logic everywhere
  • mediator communication updates one central place

Chat Room Example

A chat room mediator can manage:

  • user registration
  • public broadcasts
  • private messages
  • mute lists
  • join/leave notifications

Without Mediator

If users talk directly:

  • each user needs references to every other user
  • mute logic is duplicated
  • message routing is scattered

This creates a tangled system.


With Mediator

If users communicate through a mediator:

  • users send message requests to mediator
  • mediator decides delivery
  • message rules are centralized

This is far cleaner.


Example communication flow

Diagram
sequenceDiagram actor Alice participant Mediator actor Bob actor Charlie Alice->>Mediator: send("Hello everyone") Mediator->>Bob: receive("Alice: Hello everyone") Mediator->>Charlie: receive("Alice: Hello everyone")

Why mediator is not just a broadcaster

Mediator is not only for broadcasting messages.

It can also:

  • enforce rules
  • coordinate workflows
  • validate actions
  • resolve conflicts
  • route commands based on context

That makes it much broader than a simple notifier.


Mediator and loose coupling

One of the biggest advantages of Mediator is loose coupling.

BeforeAfter
Each object knows many othersEach object knows only mediator
Changes ripple through systemChanges stay centralized
Hard to reuse objectsEasier to reuse objects independently

Example features managed centrally

In a chat room, mediator may manage:

  • who is online
  • who muted whom
  • who should receive a message
  • whether a message is public or private

The user objects remain simple.


Mediator Pattern structure

The mediator usually has:

  • a method for registering colleagues
  • a method for receiving requests from colleagues
  • logic for routing or coordinating communication

The colleague usually has:

  • a reference to the mediator
  • a method to send messages
  • a method to receive messages

The role of colleagues

Colleagues should not depend on each other directly.

Instead:

  • a colleague sends data or requests to the mediator
  • the mediator handles the interaction

This is what keeps the code clean.


Example: Chat mediator in action

Suppose:

  • Alice sends a message
  • Bob is muted
  • Charlie is not muted

The mediator:

  • receives Alice’s message
  • checks delivery rules
  • sends it to Charlie
  • skips Bob

The logic stays in one place.


Stateful coordination

Mediator is especially useful when interactions are stateful.

Examples:

  • form field validation
  • UI button enable/disable rules
  • chat applications
  • multiplayer games
  • workflow engines

Real-world examples

DomainMediator Example
Chat appChat room coordinates messages
GUIForm mediator coordinates widget interactions
Air trafficControl tower coordinates aircraft
MatchmakingGame server coordinates players
Workflow engineCentral process manager routes tasks
Dialog boxesButton states and input field interactions

Example: GUI form

A login form may have:

  • username field
  • password field
  • login button
  • remember me checkbox

Without mediator:

  • every field directly knows about every other field

With mediator:

  • the form controller coordinates state changes

For example:

  • login button becomes enabled only when username and password are valid

GUI mediator diagram

Diagram
flowchart TD A[Username Field] --> C[Form Mediator] B[Password Field] --> C D[Login Button] --> C C --> D

Mediator vs Observer

These two patterns are often confused.

They may both involve a central object and multiple participants.

But their intent is different.

AspectMediatorObserver
Main goalCoordinate interactionsNotify observers of changes
RelationshipMany-to-one-to-many communication through mediatorOne subject notifies many observers
FocusInteraction controlEvent notification
ExampleChat roomYouTube subscriber updates

Simple distinction

Observer

One object changes, and many observers are notified.

Mediator

Many objects interact through a central coordinator.


Mediator vs Observer diagram

Diagram
flowchart LR A[Mediator] --> B[Coordinates communication] C[Observer] --> D[Broadcasts state changes]

Mediator vs Facade

These patterns also look similar, but their goals differ.

AspectMediatorFacade
PurposeCoordinate object interactionsSimplify access to a subsystem
FocusCommunication between colleaguesEasy entry point to subsystem
BehaviorColleagues interact via mediatorClient calls facade to perform work

Why Mediator improves SRP

Without mediator:

  • objects handle their own behavior
  • plus they manage communication with others
  • plus they manage cross-object rules

That is too much responsibility.

With mediator:

  • communication logic is moved out
  • each colleague becomes focused
  • mediator handles interaction rules

This is a strong SRP improvement.


Benefits of Mediator Pattern

BenefitDescription
Loose couplingObjects do not depend directly on each other
Centralized logicInteraction rules live in one place
Easier maintenanceCommunication changes are easier to manage
Better reuseColleague objects become simpler and reusable
Reduced complexityEliminates tangled object references
Easier extensionNew colleagues can be added with less impact

Drawbacks of Mediator Pattern

DrawbackDescription
Mediator can become largeA “god object” risk
More indirectionDebugging may require following mediator flow
Central bottleneckToo much logic in one place can be hard to manage

Common mistakes

MistakeProblem
Putting too much logic into mediatorMediator becomes huge and hard to maintain
Letting colleagues talk directlyBreaks the pattern
Using mediator for simple communicationOverengineering
Confusing mediator with observerDifferent intent
Failing to define clear communication rulesLeads to messy coordination

When to use Mediator Pattern

Use it when:

  • many objects interact in complex ways
  • direct communication creates tangled dependencies
  • you want to centralize coordination
  • UI components need to coordinate
  • chat or workflow rules should be managed in one place

When not to use Mediator Pattern

Avoid it when:

  • there are only a few objects
  • communication is simple
  • the mediator would become too large
  • direct communication is already clean and manageable

Example: Chat Room

#include <iostream>
#include <vector>
#include <string>
using namespace std;
 
class Mediator {
public:
    virtual void sendMessage(const string& message, const string& sender) = 0;
    virtual void registerUser(class User* user) = 0;
    virtual ~Mediator() = default;
};
 
class User {
protected:
    Mediator* mediator;
    string name;
 
public:
    User(const string& name, Mediator* mediator) : name(name), mediator(mediator) {}
 
    virtual void send(const string& message) = 0;
    virtual void receive(const string& message) = 0;
    string getName() const { return name; }
};
 
class ChatMediator : public Mediator {
private:
    vector<User*> users;
 
public:
    void registerUser(User* user) override {
        users.push_back(user);
    }
 
    void sendMessage(const string& message, const string& sender) override {
        for (User* user : users) {
            if (user->getName() != sender) {
                user->receive(sender + ": " + message);
            }
        }
    }
};
 
class ChatUser : public User {
public:
    ChatUser(const string& name, Mediator* mediator) : User(name, mediator) {}
 
    void send(const string& message) override {
        mediator->sendMessage(message, name);
    }
 
    void receive(const string& message) override {
        cout << name << " received: " << message << endl;
    }
};
 
int main() {
    ChatMediator mediator;
 
    ChatUser alice("Alice", &mediator);
    ChatUser bob("Bob", &mediator);
    ChatUser charlie("Charlie", &mediator);
 
    mediator.registerUser(&alice);
    mediator.registerUser(&bob);
    mediator.registerUser(&charlie);
 
    alice.send("Hello everyone");
    bob.send("Hi Alice");
 
    return 0;
}

C++ explanation

  • Mediator defines the communication contract
  • ChatMediator controls message routing
  • User is the colleague abstraction
  • ChatUser sends and receives through mediator
  • users do not communicate directly

Java explanation

  • the mediator stores the user list
  • each user sends messages through the mediator
  • message delivery stays centralized
  • the colleague classes remain simple

Python explanation

  • ChatMediator coordinates the room
  • users only know the mediator
  • users are decoupled from each other
  • the logic is centralized and easy to manage

Sequence Diagram: Chat Room Message Flow

Diagram
sequenceDiagram actor Alice participant Mediator actor Bob actor Charlie Alice->>Mediator: send("Hello everyone") Mediator->>Bob: receive("Alice: Hello everyone") Mediator->>Charlie: receive("Alice: Hello everyone")

Another real-world example: Air traffic control

An air traffic controller coordinates:

  • takeoff
  • landing
  • runway allocation
  • communication between planes

Planes do not coordinate directly with each other. They use the controller.

That is the Mediator pattern.


Air traffic control diagram

Diagram
flowchart TD A[Plane 1] --> C[Air Traffic Controller] B[Plane 2] --> C D[Plane 3] --> C C --> A C --> B C --> D

Another real-world example: UI form controller

A form mediator can:

  • enable or disable buttons
  • validate fields
  • trigger actions based on input
  • coordinate related widgets

This is common in GUI systems.


Benefits of Mediator

BenefitDescription
Loose couplingColleagues do not depend on each other
Centralized coordinationInteraction logic is in one place
Better maintainabilityEasier to change communication rules
Simpler colleaguesObjects focus on their own behavior
Easier extensionNew colleagues can be plugged in more cleanly

Drawbacks of Mediator

DrawbackDescription
Mediator complexityCan become too large
Hard to traceExtra layer of indirection
Central dependencyThe mediator becomes a critical component

Common mistakes

MistakeProblem
Letting colleagues directly reference each otherBreaks the pattern
Putting all business logic in mediatorMakes mediator a god object
Using mediator for trivial communicationUnnecessary complexity
Confusing with ObserverDifferent purpose and behavior
Failing to keep mediator focusedHarder to maintain

Mediator vs Observer

AspectMediatorObserver
Main purposeCoordinate complex interactionsNotify dependents of state changes
CommunicationMany objects talk through one mediatorOne subject notifies many observers
IntentManage collaborationBroadcast updates

Mediator vs Facade

AspectMediatorFacade
PurposeManage object interactionsSimplify a subsystem
FocusCollaboration logicSimple access to complex backend
UsageObjects communicate through mediatorClient calls simplified interface

Mediator and SOLID

PrincipleHow Mediator helps
SRPRemoves communication logic from colleagues
OCPNew colleagues can be added with less modification
DIPColleagues depend on mediator abstraction

Summary

The Mediator Pattern centralizes complex communication between objects.

It:

  • reduces direct dependencies
  • keeps objects from knowing too much about each other
  • moves interaction logic into one place
  • improves maintainability and flexibility

It is especially useful for:

  • chat systems
  • UI coordination
  • workflow systems
  • matchmaking systems
  • control systems

Final takeaway

The Mediator Pattern is about this simple idea:

Do not let every object talk to every other object directly. Put a mediator in the middle and let it coordinate the interaction.

That gives you:

  • less chaos
  • less coupling
  • cleaner code
  • easier maintenance

It is one of the best patterns for systems with many interacting objects.