Ey mates! today, I am talking about the Mediator Design Pattern! This is a behavioural pattern. Basically, we can say that the goal of this pattern is:
Reducing dependences between objects defining a central object which encapsulates how a set of objects interact with each other.
Promoting loose coupling.
Basically, we can to define a Mediator object as a Central Hub Object that usually sends broadcast messages to an object collection (colleagues) though in some implementation it could be sending messages to a specific a colleague. If an object wants to communicate with another MUST DO only via the Mediator object.
- When you have many objects of a similar types that need to communicate with each other.
- The communication between objects is complex
Business Situation – Iron Airport Controller 😮
Pilots of aircraft don’t communicate directly to each other when they are near an airport area, they need to talk to an air traffic controller. The main concerns of this controller are: discussing landing priorities and report to pilots about other aircraft that they are near to avoid crashes.
What happens if the air traffic controller doesn’t exist ?
Basically, all pilot of an aircraft will have to communicate with each other when they are near to the airport or they want to land.
Imagine this situation, aircraft A is near to the airport and it wants to land. It needs to communicate with all nearby aircraft to check if someone is landing at that moment or not.
Ok, you can see in my no-paint pic :p that this process is a little bit complicated. Let me show you some pseudo-code to reflect this situation:
//Creating flights var flightA = new Atr72("Aircraft A"); var flightB = new Boeing777300("Aircraft B"); var flightC = new Boeing747("Aircraft C"); var flightD = new AirbusA320Neo("Aircraft D"); //All aircraft need to know to each other flightA.Acknoledges(flightB); flightA.Acknoledges(flightC); flightA.Acknoledges(flightD); flightB.Acknoledges(flightA); flightB.Acknoledges(flightC); flightB.Acknoledges(flightD); flightC.Acknoledges(flightA); flightC.Acknoledges(flightB); flightC.Acknoledges(flightD); flightD.Acknoledges(flightA); flightD.Acknoledges(flightB); flightD.Acknoledges(flightC); //Flight A wants to land! It needs to do previous checks before landing. flightA.ExistAnotherAircraftWithPriorityToLand(); //If flight B wants to land, it needs to do the same! It needs to consult //its internal collection flightB.ExistAnotherAircraftWithPriorityToLand(); //..
Uff complicated code 🙁 All flights need to interact with each other and previous to do that, they need to know to each other (in this case using ACK method).
You can imagine that each aircraft-object needs to have a private collection of known flights. 🙁
Can you imagine if we have a lot of flights ? How do we manage the interactions ? 🙁
Mediator Pattern can help us 😀
Mediator Pattern Structure 😀
- Colleagues: classes that have some logic. Each colleague has a reference to the Mediator, in this case, via Colleague Abstract Class.
- Colleagues need to communicate with each other
- Implement some base type (abstract class or interface)
- This is optional, you can have a reference to each Colleague class (ColleagueA, ColleagueB, so on) in the Concreate Mediator Class and do a specific action when a Colleague does something. For example, if ColleagueA does something, colleagueB reacts doing something else and ColleagueC reacts doing another action. However, in a real implementation is almost a must-do to have an Abstract Class or Interface and a collection of it in the Concreate Mediator.
- Have knowledge of the Mediator Component
- Mediator: the centralized component that managed communication between the colleague components. If colleagues want to communicate with each other, they’ll need to do that via the Mediator.
- IMediator: Interface that represents a Mediator, usually has a Notify Method or some others to allow Colleagues to communicate with each other sending notifications through the mediator.
- Concrete Mediator: implements IMediator and has a Colleague collection.
Implementing the Mediator Pattern in Iron Airport Controller 😀
Let’s design that, what are the business requirements ?
- Implement an Air Traffic Controller that manages all aircraft near the Airport. Air controller will have the responsibility to verify landing priorities and aircrafts movements.
- An aircraft has to register when it is nearby
- An aircraft must have the priority to land, for this reason, when an aircraft wants to land must be asking for authorization to the Traffic Controller
- If aircraft has been authorized to land, it will have to notify when starting and finishing to land.
- When any aircraft changes its location must be to communicate that to the air controller.
You can see that we have:
- Aircraft abstract class<Colleague Abstract class>: base class of all kind of aircraft that visits the airport.
- Every aircraft has the air traffic controller as property because they have to use it to communicate with the other nearby aircraft.
- Aircrafts concrete classes <Colleague Concrete class>: All kind of aircraft that visits the airport!
- IAirTrafficController <IMediator Interface>: define all methods to interact with the colleagues.
- IronTrafficController <Mediator Concreate class>: implement IAirTrafficController.
- It has an Aircraft collection with all the nearby aircraft
Let me show you some code 😉
- This pattern is useful in specific scenarios such as chat systems and the like. Currently, CQR Pattern uses the mediator pattern too.
- Mediator Pattern encapsulates the logic to allow a set of objects to interact with each other. You can see a Mediator as a Traffic-Coordinator that consults its own state and can interact with drivers to direct the traffic but the drivers mustn’t interact with each other directly.
- Hides all coordination between colleagues
- Desacoupled colleagues! Enhances Desacoupling!
- The mediator can become very large and complex, in other words, it can become in a God Object.
That’s all mates!
I hope you enjoy it 😉
Have a look at the code on my Github!