Featured image of post BP10 - Mediator - Learn Design Pattern From Simple Things

BP10 - Mediator - Learn Design Pattern From Simple Things

In the discussion room without a teacher, you can speak or listen, but when you speak you need to make sure that everyone can hear. Therefore, a loudspeaker is a useful tool.

Mediator is a behavioral design pattern: 🖤🖤🖤🤍🤍

What is Mediator?

Mediator (Loudspeaker) is a behavioral design pattern that allows communication between objects without them having to refer to each other directly. Instead, all communication is handled by a central object called the mediator.

In this pattern, the mediator acts as an intermediary between the objects that need to communicate with each other. The objects don’t have to know anything about each other, and they don’t need to hold any references to each other.

Mediator diagram

Why use Mediator?

The Mediator pattern has the following advantages and disadvantages:

Advantages:

  • Simplifies communication between objects
  • Reduces coupling between objects
  • Centralizes control of communication

Disadvantages:

  • Can lead to the creation of a “God” object that knows too much about the system
  • Can add complexity to the system

Question: I hate the Mediator pattern, what are the alternatives?

Answer: The alternative is to have the objects communicate with each other directly. However, this can lead to increased coupling and reduced flexibility.

speaker

When to use Mediator?

Question: When should I use Mediator?

Answer: The Mediator pattern is useful when you have a complex system with many components that need to communicate with each other, and you want to minimize the dependencies between those components. It can improve flexibility, reduce complexity, and enforce encapsulation.

  • The Mediator and Observer patterns are both used to manage communication between objects in a system, but they differ in how they manage that communication.

    • In the Observer pattern, the responsibility for managing communication is divided between two types of objects: subjects and observers. The subject maintains a list of observers that need to be notified of changes to its state, and when its state changes, it sends notifications to all registered observers, updating them accordingly. Observers have no knowledge of each other and communicate only with the subject.

    • In contrast, the Mediator pattern defines an object (the mediator) that acts as a central hub for communication between objects. Objects communicate with each other via the mediator, which encapsulates the logic for how they interact with each other. The mediator has knowledge of all the objects that need to communicate with each other and can control the communication flow between them.

  • So, the key difference between the Mediator and Observer patterns is that in the Mediator pattern, the mediator object manages the communication flow between objects, while in the Observer pattern, the subject object manages the communication flow between itself and its observers.

Input:

You have a room that contains many students, who may speak or listen.

1
2
3
4
5
6
7
8
9
class Student:
    def __init__(self, name):
        self.name = name

    def speak(self, message, receiver):
        receiver.listen(message, self)

    def listen(self, message, sender):
        print(f'{self.name} hears {sender.name} say: "{message}".')

Expected Output:

If one student wants to say something, there is a simple way to let him notify the whole room.

1
2
3
4
5
Linus Torvald hears Guido van Rossum say: "Talk is cheap. Show me the code.".
Elon Musk hears Guido van Rossum say: "Talk is cheap. Show me the code.".

Guido van Rossum hears Linus Torvald say: "Software is like sex: It’s better when it’s free.".
Elon Musk hears Linus Torvald say: "Software is like sex: It’s better when it’s free.".

How to implement Mediator?

Non-Mediator implementation:

One way we could do this is by having each student communicate with each other directly, like so:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class Student:
    def __init__(self, name):
        self.name = name

    def speak(self, message, receiver):
        receiver.listen(message, self)

    def listen(self, message, sender):
        print(f'{self.name} hears {sender.name} say: "{message}".')


if __name__ == "__main__":
    guido = Student("Guido van Rossum")
    linus = Student("Linus Torvald")
    elon = Student("Elon Musk")
    
    guido.speak("Talk is cheap. Show me the code.", linus)
    guido.speak("Talk is cheap. Show me the code.", elon)
    linus.speak("Software is like sex: It’s better when it’s free.", guido)
    linus.speak("Software is like sex: It’s better when it’s free.", elon)

This approach works, but it quickly becomes unwieldy as the number of students grows. Each student would need to have a reference to every other student in the group, which becomes difficult to manage and maintain as the group size grows.

Mediator Implementation:

Instead of having each student communicate with each other directly, we can introduce a Mediator class that manages the communication between them.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class Student:
    def __init__(self, name):
        self.name = name
        self.loudspeaker = None

    def speak(self, message):
        self.loudspeaker.broadcast(message, self)

    def listen(self, message, sender):
        print(f'{self.name} hears {sender.name} say: "{message}".')


class LoudSpeaker:
    def __init__(self):
        self.students = []

    def add_student(self, student):
        student.loudspeaker = self
        self.students.append(student)

    def broadcast(self, message, sender):
        for student in self.students:
            if student != sender:
                student.listen(message, sender)


if __name__ == "__main__":
    loudspeaker = LoudSpeaker()

    guido = Student("Guido van Rossum")
    linus = Student("Linus Torvald")
    elon = Student("Elon Musk")

    loudspeaker.add_student(guido)
    loudspeaker.add_student(linus)
    loudspeaker.add_student(elon)

    guido.speak("Talk is cheap. Show me the code.")
    linus.speak("Software is like sex: It’s better when it’s free.")

The LoudSpeaker object acts as a mediator, allowing the Student objects to communicate with each other without directly referencing each other.

Conclusion:

The Mediator pattern provides a way to manage complex communication between objects in a group. By introducing a Mediator class, we can simplify the communication between objects and avoid the need for each object to have a reference to every other object in the group. This makes it easier to manage and maintain the group, especially as its size grows.

In summary, the Mediator pattern:

  • Simplifies communication between objects in a group
  • Avoids the need for each object to have a reference to every other object in the group
  • Makes it easier to manage and maintain the group, especially as its size grows

Source Code

Made with the laziness 🦥
by a busy guy