Mediator Pattern: Centralized Communication Between Objects
Overview
The Mediator Pattern is a behavioral design pattern that encapsulates how a set of objects interact. Instead of objects communicating directly with each other, they communicate through a mediator object. This loose coupling allows objects to evolve independently without tight dependencies on one another.
Structure
The pattern involves four key components:
Mediator Interface
Defines the contract for communication between colleague objects. This interface coordinates interactions and manages the exchange of messages among participants.
Concrete Mediator
Implements the mediator interface and maintains references to all colleague objects. It orchestrates communication by routing messages between participants and managing their lifecycle.
Colleague Abstract Class
Represents the base class for objects that participate in communication. Each colleague holds a reference to the mediator and uses it to send or receive messages.
Concrete Colleague
Implements specific colleague behavior. These objects never communicate directly with other colleagues; instead, they delegate all communication through the mediator.
Implemantation
Mediator Interface:
public interface ChatMediator {
void registerParticipant(Participant participant);
void sendMessage(String content, Participant sender);
}
Concrete Mediator:
import java.util.ArrayList;
import java.util.List;
public class ChatRoom implements ChatMediator {
private List<Participant> participants = new ArrayList<>();
@Override
public void registerParticipant(Participant participant) {
if (!participants.contains(participant)) {
participants.add(participant);
participant.setMediator(this);
}
}
@Override
public void sendMessage(String content, Participant sender) {
for (Participant recipient : participants) {
if (!recipient.equals(sender)) {
recipient.receiveMessage(content, sender.getName());
}
}
}
}
Colleague Abstract Class:
public abstract class Participant {
protected ChatMediator chatRoom;
private String name;
public Participant(String name) {
this.name = name;
}
public void setMediator(ChatMediator chatRoom) {
this.chatRoom = chatRoom;
}
public String getName() {
return name;
}
public abstract void receiveMessage(String content, String from);
public void sendMessage(String content) {
System.out.println(this.name + " sends: " + content);
chatRoom.sendMessage(content, this);
}
}
Concrete Colleague Classes:
public class User extends Participant {
public User(String name) {
super(name);
}
@Override
public void receiveMessage(String content, String from) {
System.out.println("[" + name + "] received from " + from + ": " + content);
}
}
Client Usage:
public class Application {
public static void main(String[] args) {
ChatMediator chatRoom = new ChatRoom();
Participant alice = new User("Alice");
Participant bob = new User("Bob");
Participant charlie = new User("Charlie");
chatRoom.registerParticipant(alice);
chatRoom.registerParticipant(bob);
chatRoom.registerParticipant(charlie);
alice.sendMessage("Hello everyone!");
bob.sendMessage("Hi Alice!");
}
}
Advantages
Decoupled Communication
Objects interact through the mediator rather than holding direct references to eachother. This separation reduces dependencies and makes the system more flexible.
Centralized Logic
Interaction rules reside in a single location. Modifying how objects communicate requires changes only to the mediator, not to individual objects.
Simplified Object Responsibilities
Colleagues focus purely on their core behavior. The complexity of inter-object communication is delegated to the mediator.
Scalability
Adding new colleagues or changing communication patterns involves modifying only the mediator, without affecting existing colleagues.
Disadvantages
Mediator Complexity
As the number of colleagues grows, the mediator can become a monolithic class handling numerous interactions, potentially violating the Single Responsibility Principle.
Potential Bottleneck
All communication flows through a single point. Under high load, the mediator may become a performance constraint.
Hidden Dependencies
While colleagues are loosely coupled, they still depend on the mediator interface. Changing the interface affects all participants.
Use Cases
UI Dialogs
Complex dialogs with interdependent components (form validation, button states, field visibility) use a mediator to coordinate state changes.
Event Systems
Publish-subscribe frameworks leverage this pattern to route events from publishers to appropriate subscribers without direct coupling.
Air Traffic Control
The control tower acts as a mediator between aircraft, coordinating takeoff, landing, and routing decisions.
Message Brokers
Enterprise message systems use mediators to route messages between producers and consumers, handling transformation and routing logic centrally.
Workflow Orchestration
Business process engines coordinate activities between tasks, handling dependencies and sequencing through a central orchestrator.