08 Jan 2025

Mediator Pattern

Overview

The Mediator Pattern is a behavioral design pattern that defines an object (the mediator) to encapsulate interactions between a group of objects. The mediator promotes loose coupling by preventing objects from referring to each other explicitly. Instead, they interact with each other through the mediator.

This pattern is especially useful when you have complex object communication and want to centralize control.

Key Participants

  1. Mediator

  • Defines the interface for communication between objects (colleagues).

  1. ConcreteMediator

  • Implements the mediator interface.

  • Coordinates the interactions between colleague objects.

  1. Colleague

  • Represents the objects that interact with each other.

  • Communicate through the mediator instead of directly with each other.

  1. Client

  • Creates and configures the mediator and colleague objects.

Implementation in Code

Example: Chat Room

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

// Concrete Mediator
class ChatRoom implements ChatMediator {
    private 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) {
            // Message should not be sent back to the sender
            if (user != sender) {
                user.receive(message);
            }
        }
    }
}

// Colleague
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);
}

// Concrete Colleague
class ConcreteUser extends User {
    public ConcreteUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }

    @Override
    public void send(String message) {
        System.out.println(this.name + " sends: " + message);
        mediator.sendMessage(message, this);
    }

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

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

        User user1 = new ConcreteUser(chatRoom, "Alice");
        User user2 = new ConcreteUser(chatRoom, "Bob");
        User user3 = new ConcreteUser(chatRoom, "Charlie");

        chatRoom.addUser(user1);
        chatRoom.addUser(user2);
        chatRoom.addUser(user3);

        user1.send("Hi everyone!");
        user2.send("Hello Alice!");
    }
}

Key Methods

  1. sendMessage(message, colleague): Handles communication between colleagues.

  1. addColleague(colleague): Adds a new colleague to the mediator.

Advantages

  1. Loose Coupling: Objects interact through the mediator, reducing dependencies between them.

  1. Centralized Control: Encapsulates interaction logic in the mediator, making it easier to manage and modify.

  1. Reusability: Colleagues can be reused with different mediators.

Disadvantages

  1. Mediator Complexity: As interactions grow, the mediator can become complex and monolithic.

  1. Single Point of Failure: The mediator becomes a critical component, and its failure can disrupt the system.

Real-World Examples

  1. Chat Rooms: Users interact through a chat room mediator.

  1. Air Traffic Control: Planes communicate with each other through a control tower mediator.

  1. UI Components: Forms where components like buttons and text boxes communicate through a mediator to avoid direct dependencies.

When to Use the Mediator Pattern?

  • When objects interact in a complex and tightly coupled way.

  • When you want to centralize communication between objects.

  • When you want to reduce the number of direct dependencies between objects.

← Back to Library