The Mediator Pattern is a behavioral design pattern that reduces chaotic dependencies between objects by forcing them to collaborate through a central mediator object.
The Problem: The "Spaghetti" Connection
Imagine you are building a Chat Room or an Air Traffic Control system. If every pilot (object) had to talk directly to every other pilot to avoid collisions, the communication network would become impossible to manage. Every time a new plane enters the area, it would need to "connect" with every existing plane.
In software, this leads to tight coupling, where changing one class requires you to change dozens of others because they are all directly linked.
The Solution: The "Tower"
Instead of objects talking to each other directly, they only talk to the Mediator. The Mediator knows who needs to receive the message and handles the routing logic. This keeps the objects (called "Colleagues") independent and simple.
Step-by-Step Java Implementation
1. The Mediator Interface
Defines the communication protocol.
// ChatMediator.java
public interface ChatMediator {
void sendMessage(String msg, User user);
void addUser(User user);
}
2. The Colleague Class
The objects that want to communicate. They only hold a reference to the mediator.
// User.java
public abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator med, String name) {
this.mediator = med;
this.name = name;
}
public abstract void send(String msg);
public abstract void receive(String msg);
}
3. Concrete Mediator
The hub that coordinates everyone.
// ChatRoom.java
import java.util.ArrayList;
import java.util.List;
public class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
@Override
public void addUser(User user) {
users.add(user);
}
@Override
public void sendMessage(String msg, User sender) {
for (User u : users) {
// Don't send the message to the person who sent it
if (u != sender) {
u.receive(msg);
}
}
}
}
Full Code for Testing
// Save as MediatorTest.java
import java.util.ArrayList;
import java.util.List;
// 1. Mediator Interface
interface ChatMediator {
void sendMessage(String msg, User user);
void addUser(User user);
}
// 2. Colleague (Abstract User)
abstract class User {
protected ChatMediator mediator;
protected String name;
public User(ChatMediator med, String name) {
this.mediator = med;
this.name = name;
}
public abstract void send(String msg);
public abstract void receive(String msg);
}
// 3. Concrete Mediator
class ChatRoom implements ChatMediator {
private List<User> users = new ArrayList<>();
public void addUser(User user) {
this.users.add(user);
}
public void sendMessage(String msg, User sender) {
for (User u : users) {
if (u != sender) {
u.receive(sender.name + ": " + msg);
}
}
}
}
// 4. Concrete Colleague
class ChatUser extends User {
public ChatUser(ChatMediator med, String name) {
super(med, name);
}
@Override
public void send(String msg) {
System.out.println(this.name + " sends -> " + msg);
mediator.sendMessage(msg, this);
}
@Override
public void receive(String msg) {
System.out.println(this.name + " received <- " + msg);
}
}
// 5. Test
public class MediatorTest {
public static void main(String[] args) {
ChatRoom room = new ChatRoom();
User ahmed = new ChatUser(room, "Ahmed");
User sara = new ChatUser(room, "Sara");
User john = new ChatUser(room, "John");
room.addUser(ahmed);
room.addUser(sara);
room.addUser(john);
ahmed.send("Hello everyone!");
System.out.println();
sara.send("Hey Ahmed, how is the project going?");
}
}
Why use Mediator?
- Decoupling: You can change how users interact by modifying only the
ChatRoomclass, without touching theUserclasses. - Simplification: Objects become easier to read and maintain because they don't contain logic about other objects.
- Centralization: Communication logic is in one place, making it easier to log or filter messages (e.g., a "Profanity Filter" in a chat room).
Real-World Example
- Air Traffic Control: Pilots don't talk to each other; they talk to the tower. The tower acts as the mediator to ensure safety.
- Java Timer: The
java.util.Timerclass acts as a mediator between the tasks to be executed and the background thread.