One-line Definition
Encapsulates object interactions inside a central coordinator, replacing chaotic many-to-many dependencies with organized one-to-many relationships.
Problem
Suppose you are building a complex UI dialog with a checkbox, a text field, and a submit button. Checking the box enables the text field. Entering text enables the button. If the checkbox directly calls methods on the text field, and the text field directly calls the button, your UI components become incredibly tangled. Reusing that checkbox in another dialog becomes impossible. The Mediator Pattern solves this by moving all interaction logic into a central Coordinator (the Dialog), so components only talk to the Dialog, never to each other.
Real-world Analogy
At an airport, planes don't communicate directly with each other — that would be chaos. Instead, all planes talk to the control tower (mediator). The tower decides who can land, who should hold, and who should take off. Each pilot only knows the tower, not the other 50 planes in the sky.
Structure
- Client
- Sets up the Mediator and registers the Colleagues with it.
- Mediator
- Interface defining the communication methods (e.g.,
notify(),sendMessage()).
- Interface defining the communication methods (e.g.,
- ConcreteMediator
- Implements the coordination logic and holds references to all Colleagues.
- Colleague
- Each participant holds a reference to the Mediator and communicates strictly through it — never directly to other Colleagues.
Diagram
classDiagram
class Client {
}
class Mediator {
<<interface>>
+notify(sender, event)
}
class ConcreteMediator {
-Colleague1 c1
-Colleague2 c2
+notify(sender, event)
}
class Colleague {
<<abstract>>
#Mediator mediator
}
class Colleague1 {
+doAction()
}
class Colleague2 {
+doAction()
}
Client --> ConcreteMediator
ConcreteMediator ..|> Mediator
Colleague1 --|> Colleague
Colleague2 --|> Colleague
Colleague o-- Mediator : communicates through
ConcreteMediator --> Colleague1 : coordinates
ConcreteMediator --> Colleague2 : coordinates
Code Walkthrough
Notice how the User objects (Colleagues) never hold references to one another. When Alice sends a message, she sends it to the ChatRoom (Mediator), which handles distributing it to everyone else.
interface ChatMediator {
void sendMessage(String message, User sender);
void addUser(User user);
}
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator mediator, String name) {
this.mediator = mediator;
this.name = name;
}
public abstract void send(String message);
public abstract void receive(String message);
public String getName() { return name; }
}
class ChatUser extends User {
public ChatUser(ChatMediator mediator, String name) {
super(mediator, name);
}
@Override
public void send(String message) {
System.out.println(name + " sends: " + message);
mediator.sendMessage(message, this);
}
@Override
public void receive(String message) {
System.out.println(name + " receives: " + message);
}
}
class ChatRoom implements ChatMediator {
private final List<User> users = new ArrayList<>();
@Override
public void addUser(User user) {
users.add(user);
}
@Override
public void sendMessage(String message, User sender) {
for (User user : users) {
// Don't send the message back to the sender
if (user != sender) {
user.receive(message);
}
}
}
}
class Main {
public static void main(String[] args) {
ChatMediator chatRoom = new ChatRoom();
User alice = new ChatUser(chatRoom, "Alice");
User bob = new ChatUser(chatRoom, "Bob");
User charlie = new ChatUser(chatRoom, "Charlie");
chatRoom.addUser(alice);
chatRoom.addUser(bob);
chatRoom.addUser(charlie);
alice.send("Hey everyone!");
}
}
Bad vs Good
Bad Approach
Problems
- Each user holds direct references to every other user.
- Adding a new user requires updating every single existing user's contact list.
- $N$ users equals $N(N-1)$ direct connections (a massive tangled web).
class User {
private String name;
private List<User> contacts = new ArrayList<>();
public void addContact(User user) { contacts.add(user); }
public void sendMessage(String message) {
for (User contact : contacts) {
contact.receive(message);
}
}
}
Better Approach
Improvements
- Zero direct user-to-user references.
- Adding a new user just means registering with the Mediator — no other users are affected.
- The tangled web is replaced by a clean star topology.
ChatMediator room = new ChatRoom();
User alice = new ChatUser(room, "Alice");
room.addUser(alice);
alice.send("Hello!"); // Mediator safely routes it
Pros vs Cons
| Pros | Cons |
|---|---|
| Replaces tightly coupled many-to-many relationships with one-to-many | The Mediator can easily evolve into an unmaintainable God Object |
| Colleagues are completely decoupled from each other | Introduces a single point of failure (if the mediator crashes) |
| Easy to change complex interaction logic in one central place | Can be massive overkill for simple, direct 1-to-1 interactions |
| Promotes the Single Responsibility Principle for Colleagues | |
| Reusing individual Colleagues in other contexts becomes easy |
When to Use
- A set of objects communicates in well-defined but complex ways, leading to tangled, unreadable code.
- You can't reuse a component in a different program because it's heavily coupled to other components.
- You want to customize distributed behavior between several classes without subclassing them all.
When Not to Use
- Objects only have simple, straightforward 1:1 relationships.
- The interaction logic is simple enough that direct communication is perfectly readable.
Real-world Examples
java.util.concurrent.ExecutorService(Mediates between tasks and threads).- View Controllers in MVC (The Controller often acts as a Mediator between the View and the Model).
- UI Frameworks (e.g., a Dialog window mediating between its buttons, text fields, and dropdowns).
Key Takeaway
The Mediator Pattern untangles chaotic object communication by forcing all objects to talk through a central hub. Use it when components become so deeply intertwined that changing one breaks five others, but guard aggressively against letting the Mediator grow into a God Object containing all your application's logic.