Open In App

Mediator Design Pattern in JavaScript | Design Pattern

Last Updated : 31 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

The Mediator pattern is a behavioral design pattern that promotes loose coupling between objects by centralizing communication between them. It’s particularly useful when you have a complex system with multiple objects that need to interact and you want to avoid the tight coupling that can arise from direct object-to-object communication.

Understanding the Mediator Pattern in JavaScript Design Pattern

The mediator pattern consists of the following key components:

  • Mediator: The Mediator is an interface or class responsible for defining the communication interface between the objects within the system. It acts as a central hub for communication and typically contains methods that allow objects to send and receive messages.
  • Concrete Mediator: This is a specific implementation of the Mediator interface. It manages the interactions between the various objects in the system. It knows how to route messages and coordinate actions between objects.
  • Colleague: Colleagues are individual objects in the system that need to communicate with each other. They are aware of the mediator but don’t have direct references to other colleagues. Instead, they send messages to and receive messages from the mediator.

Example:

Let’s illustrate the Mediator pattern with an example related to an air traffic control system. In this system, planes (Colleagues) need to communicate with each other to avoid collisions. The Air Traffic Control (Mediator) acts as the central hub for coordinating plane movements.

Javascript




// Mediator: AirTrafficControl
class AirTrafficControl {
    requestTakeoff(plane) {
        console.log(`Air Traffic Control grants takeoff clearance for ${plane.getName()}.`);
    }
 
    requestLanding(plane) {
        console.log(`Air Traffic Control clears ${plane.getName()} for landing.`);
    }
}
 
// Colleague: Plane
class Plane {
    constructor(name) {
        this.name = name;
    }
 
    getName() {
        return this.name;
    }
 
    requestTakeoff() {
        console.log(`${this.name} requests takeoff clearance.`);
        airTrafficControl.requestTakeoff(this);
    }
 
    requestLanding() {
        console.log(`${this.name} requests landing clearance.`);
        airTrafficControl.requestLanding(this);
    }
}
 
const airTrafficControl = new AirTrafficControl();
 
const plane1 = new Plane('Flight 123');
const plane2 = new Plane('Flight 456');
 
plane1.requestTakeoff();
plane2.requestLanding();


Untitled

Diagrammatical Representation of Air Traffic Control

Output:

Flight 123 requests takeoff clearance.Air Traffic Control grants takeoff clearance for Flight 123.Flight 456 requests landing clearance.Air Traffic Control clears Flight 456 for landing.

Let’s break down Air traffic control to get a better understanding:

1. Mediator

The “AirTrafficControl” class represents the Mediator in this example. It has two methods:

  • “requestTakeoff(plane)”: responsible for granting takeoff clearance for a specific plane and logs a message indicating the clearance.
  • “requestLanding(plane)”: responsible for clearing a plane for landing and logs a message indicating the clearance.

2. Colleague:

The “Plane” class represents a Colleague or an individual object in this example. It has a constructor that takes the “name” of the plane as a parameter and stores it as an instance variable.

  • “requestTakeoff()” is a method that simulates a plane requesting takeoff clearance.
  • “requestLanding()” is a method that simulates a plane requesting landing clearance.

3. Initialization:

An instance of “AirTrafficControl” is created and assigned to the variable “airTrafficControl”. This is our Mediator object. Two instances of “Plane” are created:

  • “plane1” with name ‘Flight 123’ .
  • “plane2” with the name ‘Flight 456’.

4. Interaction:

“Plane1” initiates the interaction by calling “requestTakeoff()”.

  • This method logs that ‘Flight 123’ is requesting takeoff clearance and then invokes “airTrafficControl”.
  • “requestTakeoff(this)”, where “this” refers to the “plane1” object.
  • “airTrafficControl” receives the request, logs that it grants takeoff clearance for ‘Flight 123’, and acknowledges the request. Next, “plane2” initiates the interaction by calling “requestLanding()”.
  • This method logs that ‘Flight 456’ is requesting landing clearance and then invokes “airTrafficControl”.
  • “requestLanding(this)”, where “this” refers to the “plane2” object. Again, “airTrafficControl” receives the request, logs that it clears ‘Flight 456’ for landing, and acknowledges the request.

This example demonstrates how the Mediator pattern facilitates communication between objects (planes) in a centralized and loosely coupled manner. The “AirTrafficControl” acts as a central hub, coordinating and managing the interactions between the planes, enabling them to request and receive clearances for takeoff and landing.

Advantages of the Mediator method in JavaScript Design Pattern

  • Decoupling: The Mediator pattern reduces direct dependencies between objects, promoting a more loosely coupled system. Colleagues only need to know about the Mediator, not each other, which makes the system more maintainable and extensible.
  • Centralized Control: Centralizing communication in a Mediator can simplify complex interactions in a system. This central hub can enforce rules, coordinate actions, and ensure that communication remains organized.
  • Reusability: Mediators can be reused across different scenarios or projects. Once you have a well-defined Mediator interface or class, you can apply it to various situations where you need to manage interactions between objects.
  • Promotes Single Responsibility Principle: The Mediator pattern encourages the Single Responsibility Principle by isolating communication-related logic in one place, making the codebase cleaner and more modular.

Disadvantages of the Mediator Method in JavaScript Design Pattern

  • Complexity: In some cases, introducing a Mediator can add complexity to the system, especially if you have a small number of objects or if the interactions between objects are straightforward.
  • Performance Overhead: Managing communication through a Mediator can introduce some performance overhead, as all messages pass through this central point. However, this overhead is usually negligible in most applications.
  • Maintaining the Mediator: If the system becomes overly complex or if there are frequent changes in communication requirements, maintaining the Mediator can become challenging.
  • Potential for God Object: Care should be taken not to turn the Mediator into a “God Object” that knows too much about the system. It should focus on facilitating communication, not on handling all logic.

Conclusion

The Mediator design pattern is a valuable tool for managing complex interactions between objects in a system while maintaining loose coupling and modularity. It encourages a more organized and maintainable codebase by centralizing communication. When used appropriately, the Mediator pattern enhances code reusability and promotes the Single Responsibility Principle. However, it’s essential to strike a balance and avoid overcomplicating the system with unnecessary mediators. By understanding and applying the Mediator pattern effectively, you can design more flexible and scalable software systems.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads