Introduction to the Mediator Pattern

The Mediator pattern is a behavioral design pattern that defines an object that encapsulates how a set of objects interact. This pattern promotes loose coupling by keeping objects from referring to each other explicitly and allows their interaction to be varied independently.

Key Concepts

  • Mediator: An interface that defines the communication between colleague objects.
  • Concrete Mediator: Implements the Mediator interface and coordinates communication between colleague objects.
  • Colleague: Objects that communicate with each other through the mediator.

When to Use the Mediator Pattern

  • When a set of objects communicate in complex but well-defined ways.
  • When reusing an object is difficult because it refers to and communicates with many other objects.
  • When a behavior that's distributed between several classes should be customizable without a lot of subclassing.

Example Scenario

Consider a chat room application where users can send messages to each other. Instead of each user object knowing about every other user object, a mediator (ChatRoom) can handle the communication.

UML Diagram

+---------------------+        +---------------------+
|      Mediator       |<------>|     Colleague       |
|---------------------|        |---------------------|
| +sendMessage()      |        | +receiveMessage()   |
+---------------------+        +---------------------+
         ^                              ^
         |                              |
         |                              |
+---------------------+        +---------------------+
|  Concrete Mediator  |        |     User            |
|---------------------|        |---------------------|
| +sendMessage()      |        | +receiveMessage()   |
+---------------------+        +---------------------+

Code Example

Mediator Interface

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

Concrete Mediator

import java.util.ArrayList;
import java.util.List;

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

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

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

    @Override
    public void sendMessage(String message, User user) {
        for (User u : this.users) {
            // Message should not be received by the user sending it
            if (u != user) {
                u.receiveMessage(message);
            }
        }
    }
}

Colleague

public abstract class User {
    protected ChatMediator mediator;
    protected String name;

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

    public abstract void sendMessage(String message);
    public abstract void receiveMessage(String message);
}

Concrete Colleague

public class ChatUser extends User {

    public ChatUser(ChatMediator mediator, String name) {
        super(mediator, name);
    }

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

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

Client Code

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

        User user1 = new ChatUser(chatMediator, "Alice");
        User user2 = new ChatUser(chatMediator, "Bob");
        User user3 = new ChatUser(chatMediator, "Charlie");
        User user4 = new ChatUser(chatMediator, "Diana");

        chatMediator.addUser(user1);
        chatMediator.addUser(user2);
        chatMediator.addUser(user3);
        chatMediator.addUser(user4);

        user1.sendMessage("Hello, everyone!");
    }
}

Explanation

  1. ChatMediator Interface: Defines the contract for sending messages and adding users.
  2. ChatRoom Class: Implements the ChatMediator interface and manages the communication between users.
  3. User Class: Abstract class representing a user in the chat room.
  4. ChatUser Class: Concrete implementation of the User class.
  5. MediatorPatternDemo Class: Demonstrates the use of the Mediator pattern.

Practical Exercise

Exercise

Create a simple traffic light system using the Mediator pattern. The system should have three lights (Red, Yellow, Green) and a TrafficMediator that controls the state transitions.

Solution

Mediator Interface

public interface TrafficMediator {
    void changeLight(TrafficLight light);
}

Concrete Mediator

public class TrafficController implements TrafficMediator {
    private TrafficLight redLight;
    private TrafficLight yellowLight;
    private TrafficLight greenLight;

    public TrafficController() {
        this.redLight = new RedLight(this);
        this.yellowLight = new YellowLight(this);
        this.greenLight = new GreenLight(this);
    }

    @Override
    public void changeLight(TrafficLight light) {
        if (light instanceof RedLight) {
            System.out.println("Red Light -> Green Light");
            greenLight.turnOn();
        } else if (light instanceof GreenLight) {
            System.out.println("Green Light -> Yellow Light");
            yellowLight.turnOn();
        } else if (light instanceof YellowLight) {
            System.out.println("Yellow Light -> Red Light");
            redLight.turnOn();
        }
    }

    public void start() {
        redLight.turnOn();
    }
}

Colleague

public abstract class TrafficLight {
    protected TrafficMediator mediator;

    public TrafficLight(TrafficMediator mediator) {
        this.mediator = mediator;
    }

    public abstract void turnOn();
}

Concrete Colleagues

public class RedLight extends TrafficLight {
    public RedLight(TrafficMediator mediator) {
        super(mediator);
    }

    @Override
    public void turnOn() {
        System.out.println("Red Light is ON");
        mediator.changeLight(this);
    }
}

public class YellowLight extends TrafficLight {
    public YellowLight(TrafficMediator mediator) {
        super(mediator);
    }

    @Override
    public void turnOn() {
        System.out.println("Yellow Light is ON");
        mediator.changeLight(this);
    }
}

public class GreenLight extends TrafficLight {
    public GreenLight(TrafficMediator mediator) {
        super(mediator);
    }

    @Override
    public void turnOn() {
        System.out.println("Green Light is ON");
        mediator.changeLight(this);
    }
}

Client Code

public class TrafficLightDemo {
    public static void main(String[] args) {
        TrafficController controller = new TrafficController();
        controller.start();
    }
}

Explanation

  1. TrafficMediator Interface: Defines the contract for changing lights.
  2. TrafficController Class: Implements the TrafficMediator interface and manages the state transitions of the traffic lights.
  3. TrafficLight Class: Abstract class representing a traffic light.
  4. RedLight, YellowLight, GreenLight Classes: Concrete implementations of the TrafficLight class.
  5. TrafficLightDemo Class: Demonstrates the use of the Mediator pattern in a traffic light system.

Common Mistakes and Tips

  • Direct Communication: Avoid direct communication between colleague objects. Always use the mediator for communication.
  • Complex Logic in Colleagues: Keep the logic in colleague objects simple. The mediator should handle the complex interactions.
  • Overuse: Do not overuse the Mediator pattern. It is best suited for complex interactions that are difficult to manage otherwise.

Summary

The Mediator pattern helps in reducing the complexity of communication between multiple objects by centralizing the communication logic in a mediator object. This promotes loose coupling and makes the system easier to maintain and extend. By following the examples and exercises provided, you should now have a solid understanding of how to implement and use the Mediator pattern in your own projects.

© Copyright 2024. All rights reserved