Skip to main content

Mediator Design Pattern: Centralized Communication

Table of Contents

  1. Introduction: What is the Mediator Pattern?
  2. Complex Communication Between Objects
  3. How the Mediator Pattern Works
  4. Implementation Example (Java)
  5. Advantages of Using the Mediator Pattern
  6. Disadvantages of Using the Mediator Pattern
  7. Use Cases and Real-World Examples
  8. Mediator Pattern vs. Observer Pattern
  9. Conclusion

1. Introduction: What is the Mediator Pattern?

The Mediator pattern is a behavioral design pattern that defines an object that encapsulates how a set of objects interact. Instead of objects communicating directly with each other, they communicate through the mediator object. This centralizes the communication logic and reduces the dependencies between the objects.

Think of an air traffic controller. Pilots don't communicate directly with each other; they communicate through the air traffic controller. The controller manages all the communication and ensures that everything runs smoothly. The air traffic controller is the mediator.

Mediator Pattern

Explanation of the Diagram

Participants

  • Client (C): The entity setting up the system and initiating actions (also acts as User1 here).
  • ChatMediator (M): The mediator coordinating communication between users.
  • User1 (U1), User2 (U2), User3 (U3): Colleague objects (users) interacting through the mediator.

Flow

Setup

  1. The Client creates a ChatMediator.
  2. The Client creates User objects (User1, User2, User3), each registering with the ChatMediator.

Message Sending

  1. The Client (acting as User1) calls sendMessage("Hello everyone!") on User1.
  2. User1 forwards the message to the ChatMediator, indicating itself as the sender.
  3. The ChatMediator broadcasts the message to User2 and User3 (but not back to User1).

Message Receiving

  1. User2 and User3 receive the message via the ChatMediator.
  2. Each user displays the received message locally.

Mediator Pattern Role

  • Centralization: The ChatMediator handles all communication, preventing direct User-to-User interactions.
  • Decoupling: Users don’t need references to each other; they only know the mediator.
  • Control: The mediator can filter, route, or modify messages as needed.

2. Complex Communication Between Objects

When many objects in a system need to communicate with each other, the communication paths can become complex and tangled. This can lead to several problems:

  • Tight Coupling: Objects become tightly coupled to each other, making it difficult to change or reuse them.
  • Code Complexity: The communication logic can become scattered throughout the system, making it hard to understand and maintain.
  • Reduced Reusability: Objects become less reusable because they are tied to specific communication patterns.

3. How the Mediator Pattern Works

The Mediator pattern solves these problems by:

  • Defining a Mediator Interface: This interface specifies the methods that the colleague objects use to communicate with the mediator.
  • Creating a Concrete Mediator Implementation: This class implements the Mediator interface and handles the communication between the colleagues.
  • Defining Colleague Classes: These classes represent the objects that communicate with each other through the mediator. Each colleague has a reference to the mediator.

When a colleague object needs to communicate with another colleague, it sends a message to the mediator. The mediator then forwards the message to the appropriate colleague. This centralizes the communication logic and decouples the colleagues from each other.

Implementation Example

Let's illustrate with a Java example of a chat room.

Defining the Mediator Interface

interface ChatMediator {
void sendMessage(String message, User user);
void addUser(User user);
}

Concrete Mediator Implementation

class ChatRoom implements ChatMediator {
private List<User> users;

public ChatRoom() {
this.users = new ArrayList<>();
}

@Override
public void sendMessage(String message, User user) {
for (User u : users) {
if (u != user) {
u.receiveMessage(message);
}
}
}

@Override
public void addUser(User user) {
this.users.add(user);
}
}

Colleague Classes

class User {
private String name;
private ChatMediator mediator;

public User(String name, ChatMediator mediator) {
this.name = name;
this.mediator = mediator;
}

public void sendMessage(String message) {
mediator.sendMessage(message, this);
}

public void receiveMessage(String message) {
System.out.println(this.name + " received: " + message);
}
}

Client Code Example

public class Client {
public static void main(String[] args) {
ChatMediator mediator = new ChatRoom();

User john = new User("John", mediator);
User jane = new User("Jane", mediator);
User david = new User("David", mediator);

mediator.addUser(john);
mediator.addUser(jane);
mediator.addUser(david);

john.sendMessage("Hi everyone!");
jane.sendMessage("Hello John!");
}
}

Advantages of Using the Mediator Pattern

  • Decoupling: Colleagues are decoupled from each other.
  • Simplified Code: The communication logic is centralized, making the code easier to understand and maintain.
  • Increased Reusability: Colleagues become more reusable because they are not tied to specific communication patterns.
  • Simplified Object Interactions: Reduces the complex many-to-many relationships between objects to simpler one-to-many relationships with the mediator.

Disadvantages of Using the Mediator Pattern

  • Centralization Overhead: The mediator can become a central point of control, which can add some overhead.
  • Potential Bottleneck: If the mediator is not designed efficiently, it can become a bottleneck in the system.
  • Increased Complexity (Initially): Introducing a mediator can add some initial complexity to the design.

Use Cases and Real-World Examples

  • Chat Rooms: As shown in the example.
  • Air Traffic Control: As mentioned earlier.
  • GUI Frameworks: Mediators are used to manage communication between GUI components.
  • Event Management Systems: A mediator can manage the distribution of events to different listeners.

Mediator Pattern vs. Observer Pattern

Both patterns deal with communication between objects. However:

  • Mediator Pattern: Centralizes communication through a mediator object. Objects communicate with the mediator.
  • Observer Pattern: One object (the subject) notifies multiple other objects (the observers) of changes in its state. Objects are loosely coupled, and the subject doesn't know the specifics of the observers. Objects communicate to the subject to register for notifications.

The key difference is that the Mediator pattern manages bidirectional communication between objects, while the Observer pattern is typically used for one-to-many notifications.

Conclusion


info

The Mediator pattern is a powerful tool for managing complex communication between objects. It promotes loose coupling, simplifies code, and increases reusability. While there might be some initial overhead, the benefits of using the Mediator pattern often outweigh the costs, especially in complex systems with many interacting objects. It helps create a more organized and maintainable system architecture.