The Mediator design pattern is a behavioral pattern that defines an object (the mediator) that encapsulates the communication and coordination between a group of objects (colleagues). Instead of colleagues directly interacting with each other, they communicate through the mediator, enabling loose coupling and reducing dependencies. The Mediator pattern promotes the centralization of communication logic and simplifies complex interactions between objects.

Key Components of the Mediator Pattern

  1. Mediator: The Mediator is an interface or abstract class that defines the communication contract between colleagues. It typically includes methods for colleagues to register, communicate, and coordinate with each other.
  2. Concrete Mediator: The Concrete Mediator implements the Mediator interface and provides the actual implementation of the communication and coordination logic among colleagues.
  3. Colleague: The Colleague represents the individual objects that interact with each other. They are aware of the Mediator interface and communicate through it.

Example:

Mediator Pattern in Building Collaborations: Let’s consider a scenario where multiple buildings need to collaborate on a construction project. Each building has its own responsibilities, such as foundation construction, electrical wiring, and plumbing. We can use the Mediator pattern to facilitate communication and coordination among the buildings.

interface Mediator {
    void registerBuilding(Building building);

    void sendMessage(Building sender, String message);
}

class ConstructionMediator implements Mediator {
    private List<Building> buildings;

    public ConstructionMediator() {
        buildings = new ArrayList<>();
    }

    @Override
    public void registerBuilding(Building building) {
        buildings.add(building);
    }

    @Override
    public void sendMessage(Building sender, String message) {
        for (Building building : buildings) {
            if (building != sender) {
                building.receiveMessage(message);
            }
        }
    }
}

class Building {
    private String name;
    private Mediator mediator;

    public Building(String name, Mediator mediator) {
        this.name = name;
        this.mediator = mediator;
    }

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

    public void receiveMessage(String message) {
        System.out.println("Received message in building " + name + ": " + message);
    }
}

In the above example, we have the Mediator interface that defines the methods for registering buildings and sending messages. The ConstructionMediator is the concrete implementation of the Mediator interface. It maintains a list of registered buildings and handles the communication among them.

The Building class represents individual buildings that collaborate on the construction project. Each building has a reference to the Mediator and can send messages through it.

By utilizing the Mediator pattern, we can establish a centralized communication channel among the buildings. Instead of direct interactions between buildings, they communicate through the mediator, which ensures loose coupling and simplifies the collaboration process.

Benefits and Use Cases of the Mediator Design Pattern

The Mediator design pattern offers several benefits:

  1. Loose Coupling: The Mediator pattern promotes loose coupling between objects by encapsulating their interactions through a mediator. It reduces dependencies and simplifies communication channels.
  2. Simplified Collaboration: The pattern simplifies complex collaborations by centralizing the communication logic. Instead of objects needing to be aware of each other, they rely on the mediator to facilitate communication.
  3. Extensibility: The Mediator pattern supports easy addition or removal of colleagues without affecting other objects. This makes it suitable for scenarios where new objects need to be added dynamically.
  4. Centralized Control: The pattern provides a centralized point of control for communication and coordination, making it easier to manage and monitor interactions.

The Mediator pattern finds use in various scenarios, including:

  • Collaborative Systems: The pattern is commonly used in systems where multiple objects need to communicate and coordinate their actions, such as collaborative document editing or distributed systems.
  • Event-driven Architectures: In event-driven systems, the Mediator pattern can be employed to handle and route events between different components or modules.
  • GUI Components: The pattern is applicable in graphical user interface frameworks, where different UI components need to communicate and respond to user interactions.
  • Multiplayer Games: In multiplayer game development, the Mediator pattern can facilitate communication and synchronization between game entities or players.

Conclusion

The Mediator design pattern offers a powerful solution for managing and coordinating interactions between objects. By centralizing the communication logic through a mediator, the pattern promotes loose coupling, simplifies collaborations, and enhances the flexibility of interactions.

In this blog post, we explored the Mediator pattern and its practical application in the context of building collaborations. Using the example of buildings collaborating on a construction project, we demonstrated how the Mediator pattern simplifies communication and reduces dependencies.

By leveraging the Mediator pattern, software engineers and architects can design systems that effectively manage complex interactions, leading to more modular, flexible, and maintainable code. So, the next time you encounter a scenario that involves multiple objects communicating and coordinating their actions, consider applying the Mediator pattern to streamline your interactions and enhance the efficiency of your system.