Through the self-education journey, I finally understood a Mediator. The Mediator Design Pattern can be a beneficial tool in your toolbox when you progress as a Developer.
This tutorial expects you to know the basics of C# language and Object-oriented Programming.
A Mediator Design Pattern (Mediator) was first-time officially introduced in a book titled Design Patterns: Elements of Reusable Object-Oriented Software.
Ugly dependency graph is precisely what you and I should try to avoid. Loose coupling is one of the ways how to do this. And Mediator is the concrete implementation of doing it.
The Mediator enables an object to avoid referring directly to each other by encapsulating communication in a central Mediator object.
Imagine a bunch of objects in your codebase. If each of the objects must relate and communicate with all other purposes, this could get ugly in a hurry.
Developer friendly explanation
With Mediator, we create a central Mediator object. This single object has the sole responsibility for maintaining references to the objects in our “bunch of objects”.
It is also responsible for relaying any messages or communication between and to these objects. You can think of Mediator of like a communication hub.
A Mediator commonly consists of these four components:
- Mediator — Defines communication between Colleagues.
- Concrete Mediator — Implements communication between Colleagues.
- Colleague — Communicates only with the Mediator.
- Concrete Colleague — Receive messages from the Mediator.
Relationship between components
Mediator is typically an abstract-based class.
Concrete Mediator inherits from the base Mediator and implements the communication that was primarily defined by the contract or base methods in the Mediator.
Colleague is an abstract-based class also but represents a related collection of objects. It references only its Mediator and communicates with it. You can think of this as bidirectional between the Mediator and Colleagues.
Concrete Colleague is simply a different type of subclasses that inherit from the abstract Colleague base class and defines specific behavior.
Let’s dive into code and implement our very first Mediator. First, what we will need to create is an abstract class named Mediator and its abstract method Send.
Then create an abstract class Colleague.
As you can see, I added a little bit of implementation.
The first thing is that we have a constructor for the
Colleague that takes in a Mediator and sets it into a protected field.
Then I implemented method
Send which will send a message to that Mediator we stored into the protected field via its Send method.
Finally, I have an abstract
HandleNotification method at the bottom. Think about this as we need somewhere to receive messages.
Now Let’s add Concrete Colleagues that inherit from this abstract
While I inherit from abstract class
Colleague, I implemented the method
HandleNotification. Implementation is a simple printing of notification of received message into the console.
The last class needs to be defined, and it is a
Look at the
Send method. As you can see, Mediator is handling communication between objects. In this concrete situation, I am passing the message from
Colleague2 and conversely.
Now let’s go into Program.cs to use all this.
Let’s instantiate the
ConcreteMediator. Then I need instances of both Colleagues as objects
c2. Notice that I am passing the
Mediator into both. Afterward, we must also set both of Mediator’s properties and by that is defined already mentioned bidirectional references. Now we can’t start to send a message. Build and run the code.
We can see that messages were delivered and received by
Colleagues to each other.
The mediator is a communication hub between objects. It resolves the correct message direction for you. One of the main benefits of the Mediator is the ability to encapsulate object interaction with loose coupling between objects. Remember, patterns are just guiding rails, not prescriptive implementation rules that are set in stone. Many different implementations are acceptable.