What is the mediator?
In short: A Mediator is an event channel that stands between all components and manages the interaction between the components.
To understand this in detail, we first need to understand the difference between Observer and the publish-subscribe pattern.

ObserverA subject (object) contains the entire logic for event management and the event handlers are stored here. This means that all other objects can only subscribe to this one subject => a one-to-many connection.
Publish/SubscribeThe complete communication logic is carried out within an event channel. This event channel contains all interfaces and stores all event handlers. Every object can publish and subscribe to this event channel => a many-to-many connection.
The Mediator extends the principle of the publish-subscribe pattern. It is used at application level and takes care of the event handling of all components. The advantages of the publish-subscribe pattern remain, but the mediator prevents complex relationships between components. There are no strict dependencies between components.

Example: The Database has updated its data and wants to make this available to the Diagram communicate. Here the Database not directly a method from the Diagram interface, but it would call an event for the Mediator publish. The Diagram listens to this event and wants to create a new Shape draw. For this, the Diagram a new event at the Mediator. The Shape listens to this event and carries out its logic. In short: everything goes through the Mediator.
Code-Example
Here is a code example of how the data update from the example above could look:
class Mediator{
constructor() {
// Collection of handlers
let handlers = {};
// Method to publish the change
this.publish = function(name, args) {
handlers[name].map(handler => handler(args));
};
// Method for subscription on event
this.subscribe = function(name, handler) {
if (typeof handlers[name] === 'undefined') {
handlers[name] = [];
}
handlers[name].push(handler);
}
// Method to unsubscribe from event
this.unsubscribe = function(name, handlers) {
handlers[name] = handlers[name].filter(storedHandler => storedHandler !== handler);
};
}
}
class Shape {
constructor(name, channel) {
function init() {
/** ... some load logic ... **/
channel.publish('loadedShape', this);
}
this.name = name;
init();
};
}
class Diagram {
constructor(channel) {
function init() {
channel.subscribe('newShape', shape => {
new Shape(shape, channel);
});
channel.subscribe('loadedShape', shapeObj => {
console.log(shapeObj);
})
}
init();
}
}
class Database {
constructor(channel) {
function init() {
this.getUpdates();
}
this.getUpdates = function() {
let addedEntities = ['rect1', 'rect2', 'rect3'];
addedEntities.map(ent => channel.publish('newShape', ent));
}
init();
}
}
(function() {
let mediator = new Mediator();
let diagram = new Diagram(mediator);
let database = new Database(mediator);
})()
As soon as the getUpdates() function from the Database is called, the data is published in the "newShape" channel. The Diagram listens to this channel "newShape" and initializes a new shape there. Shape (simplified). In the Shape the corresponding logic is then called. As soon as this is complete, the "loadedShape" channel is published with the associated data. Diagram listens to "loadedShape" and executes a console.log in our example.
Relevance in JavaScript
As the number of components increases, so does the complexity. The use of a Mediator makes sense, as it simplifies the code and increases readability.
Source: https://soshace.com/programming-patterns-publishersubscriber-mediator/


