Understanding the Mediator Pattern

A stunning aerial shot of the Arfa Software Technology Park building in Lahore showcasing modern architecture.
A stunning aerial shot of the Arfa Software Technology Park building in Lahore showcasing modern architecture.

The Mediator pattern is a behavioral design pattern that allows objects to communicate with each other indirectly, through a central mediator object. This approach aims to reduce direct dependencies between objects, thereby promoting looser coupling and enhancing maintainability.

1. Introduction

The Mediator Pattern defines an object that encapsulates how a set of objects interact. Instead of objects interacting directly with one another, which can lead to a tightly coupled system, all communication is handled via a mediator object. This pattern is particularly useful in systems where many objects need to collaborate, but direct connections between them would create a complex, unmanageable web of dependencies.

Where it is used:

  • Graphical User Interfaces (GUIs): UI components (buttons, text fields, checkboxes) often interact. A mediator can manage their state changes and actions, ensuring components react correctly without knowing about each other.
  • Chat Applications: Participants in a chat room don’t send messages directly to each other; they send them to the chat room (mediator), which then dispatches them to other participants.
  • Air Traffic Control Systems: Aircraft (colleagues) do not communicate directly but through an air traffic controller (mediator).

2. Implementation Example

Consider a simple chat room where users send messages without directly knowing other users. The ChatRoom acts as the mediator.

# Mediator Interface
class ChatRoomMediator:
    def send_message(self, message: str, participant: 'Participant'):
        """Sends a message from one participant to others."""
        pass

# Concrete Mediator
class ChatRoom(ChatRoomMediator):
    def __init__(self):
        self._participants = []

    def add_participant(self, participant: 'Participant'):
        """Adds a participant to the chat room."""
        self._participants.append(participant)

    def send_message(self, message: str, sender: 'Participant'):
        """Dispatches message to all participants except the sender."""
        for participant in self._participants:
            if participant != sender:
                participant.receive_message(message)

# Colleague Abstract Class
class Participant:
    def __init__(self, name: str, mediator: ChatRoomMediator):
        self.name = name
        self.mediator = mediator

    def send(self, message: str):
        """Sends a message via the mediator."""
        print(f"{self.name} sends: '{message}'")
        self.mediator.send_message(message, self)

    def receive_message(self, message: str):
        """Receives a message from the mediator."""
        print(f"{self.name} receives: '{message}'")

# Concrete Colleague
class User(Participant):
    def __init__(self, name: str, mediator: ChatRoomMediator):
        super().__init__(name, mediator)

# Usage
if __name__ == "__main__":
    chat_room = ChatRoom()

    alice = User("Alice", chat_room)
    bob = User("Bob", chat_room)
    charlie = User("Charlie", chat_room)

    chat_room.add_participant(alice)
    chat_room.add_participant(bob)
    chat_room.add_participant(charlie)

    print("--- Alice sends a message ---")
    alice.send("Hello everyone!")

    print("\n--- Bob sends a message ---")
    bob.send("Hi Alice, how are you?")

3. Mermaid Diagram

The diagram illustrates how ColleagueA and ColleagueB interact indirectly through the Mediator.

graph TD;
    ColleagueA -- Request --> Mediator[Mediator];
    Mediator -- Action --> ColleagueB;

4. Pros & Cons

The Mediator pattern offers several advantages and some potential drawbacks:

Pros:

  • Reduced Coupling: Components (colleagues) become independent, knowing only their mediator. This makes them more reusable and easier to maintain.
  • Improved Maintainability: Changes in interaction logic are centralized within the mediator, reducing the impact on individual components.
  • Simplified Component Logic: Each component focuses solely on its own responsibility, delegating complex communication logic to the mediator.
  • Centralized Control: The interaction logic is encapsulated in one place, making it easier to understand, manage, and modify.

Cons:

  • Mediator Becomes a God Object: If not designed carefully, the mediator can become overly complex, accumulating too much logic and becoming a single point of failure or a bottleneck in the system.
  • Increased Complexity (Initial): For very simple interactions, introducing a mediator can add unnecessary layers of abstraction, making the system more complex than required.
  • Performance Overhead: Indirect communication might introduce a slight performance overhead, though this is typically negligible in most applications.

5. References

Last updated on