Mediator pattern

Definition

Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.

Introduction

Well-designed enterprise applications are composed of lightweight objects with specific responsibilities divided between them in accordance to the Single Responsibility principle, one of the SOLID design principles. However, the benefits of an application composed of a large number of small objects comes with a challenge – the communication between them. Objects need to communicate to perform business requirements, and as the number of objects grow, connections between the objects required can quickly become unmanageable. In addition, the objects that are communicating directly needs to know about each other - they are all tightly coupled - and this violates the basics of the SOLID principles. The Mediator pattern is a proven solution to address such recurring challenges and the problems arising out of them.

The Mediator pattern says that instead of allowing a set of objects to directly interact between themselves, define an object (mediator) that will handle the interactions. What the mediator essentially says to such set of objects is talk with me instead of talking among yourselves. This figure conceptually shows how objects interact without and with a mediator.

The Mediator pattern, as shown in the above figure employs a mediator object to enable other objects of the application to interact without knowing each other’s identities. The mediator also encapsulates a protocol that objects can follow.

It is the mediator object that encapsulates all interaction logic between objects in a system. Therefore, if an existing object is updated with new interaction rules or a new object is added to the system, it is only the mediator object that you need to update. In the absence of the mediator, you would need to update all the corresponding objects that which to interact. Through the use of the Mediator Pattern your code becomes more encapsulated, thus changes are not as extensive.

Participants

Imagine a war zone where armed units are moving into the enemy’s territory. Armed units can include soldier, tank, grenadier, and sniper units. The strategy being employed is that whenever one unit attacks, other units should stop attacking and take cover. To do so, the unit that is currently attacking needs to notify the other units.

In the programming world, you can easily model this requirement by creating classes for each armed unit. In each class, whenever its object is about to start attacking, you can implement the logic to notify objects of the other classes. Now, imagine that a new unit joins in. The consequence – all the existing classes need to be updated. In the worst case, imagine that the battle tactics change so that both the soldier and sniper units can now attack simultaneously. Again, the consequence is a lot of changes to the code base. We can address such challenges, similarly as done in real life. Place a Commander in a base camp that will act as the mediator. All units, instead of communicating between themselves will communicate with the mediator. The mediator based on the notifications received from some units can send request to one or more other units to perform actions as requirements demand.

With our example, let’s look at the participants of the Mediator pattern.

  1. Mediator (Commander): Is an interface that declares methods for communicating with Colleague objects.
  2. ConcreteMediator (CommanderImpl): Implements Mediator. This class maintains and coordinates Colleague objects.
  3. Colleague(SoldierUnit and TankUnit): Communicates with its Mediator when their state changes and responds to requests from the Mediator.

Mediator Pattern in the Spring Framework

In Spring MVC, there is a great example of the Mediator Pattern in action with how Spring MVC uses the Dispatcher Servlet in conjunction with the controllers.

Consider this diagram from the official Spring MVC documentation:

Here, we can see how the Front Controller (aka Dispatcher Servlet) acts as a mediator between web request, the controller objects, and the view objects. The individual controllers are unaware of each other. Each controller is also blissfully unaware of the context of the web request. The view templates are unaware of the each other, and the controllers. It is the responsibility of the Front Controller to decide which controller and which view template to utilize when building a response to a web request.

Because of the usage of the Mediator pattern, changes in the individual controllers do not affect other controllers. Changes in the web request object, will not cause downstream changes in the controllers, nor views.

Summary

The Mediator pattern is considered one of the most important and widely adopted patterns. It is mainly because of its ability to encapsulate communication logic between sets of objects to fulfill some business requirements. A disadvantage of this pattern often being discussed in the developer community is that the mediator object can gradually get inflated and finally become overly complex. But, by following SOLID design principles, specifically the Single Responsibility principle, you can segregate the responsibilities of a mediator into separate classes.

Reading material

https://github.com/explorer436/programming-playground/tree/main/java-playground/design-pattern-samples/design-pattern-examples

  1. https://springframework.guru/gang-of-four-design-patterns/mediator-pattern/