Mediator Design Pattern
Structural: Mediator Pattern
What is the Mediator Design Pattern?
View Answer:
The objects participating in this pattern are:
Mediator -- example code: Chatroom
- It specifies an interface for interacting with Colleague objects
- Maintains references to Colleague objects
- Manages central control over operations
Colleagues -- example code: Participants
- objects that the Mediator is mediating
- each instance maintains a connection (reference) to the Mediator
Let's consider an example of a Chat Room where multiple users can send and receive messages.
Here is a JavaScript implementation of the Mediator Pattern:
class User {
constructor(name) {
this.name = name;
this.chatRoom = null;
}
send(message, to) {
this.chatRoom.send(message, this, to);
}
receive(message, from) {
console.log(`${from.name} to ${this.name}: ${message}`);
}
}
class ChatRoom {
constructor() {
this.users = {};
}
register(user) {
this.users[user.name] = user;
user.chatRoom = this;
}
send(message, from, to) {
if (to) {
// Single user message
to.receive(message, from);
} else {
// Broadcast message
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
}
}
}
// Create users
let brad = new User('Brad');
let jeff = new User('Jeff');
let sara = new User('Sara');
// Create chatroom
let chatroom = new ChatRoom();
// Register users in chatroom
chatroom.register(brad);
chatroom.register(jeff);
chatroom.register(sara);
// Users send and receive messages
brad.send('Hello Jeff', jeff);
sara.send('Hello Brad, you are the best!', brad);
jeff.send('Hello Everyone!');
In the above example, User
objects can send and receive messages from each other but they are doing it using the ChatRoom
mediator. The ChatRoom
object knows how to redirect the messages among users and it encapsulates this logic so that the User
objects don't need to know about the details of each other directly. This makes User
objects loosely coupled and they can communicate with each other effectively via the ChatRoom
mediator.
The Mediator pattern belongs to which pattern category?
View Answer:
When should you utilize the JavaScript Mediator Pattern?
View Answer:
- If your system has several components that must communicate with one another.
- To avoid tight object coupling in a system with many objects.
- To enhance code readability.
- To make it easier to maintain code.
- If communication between objects gets complicated or impedes code reusability
What are the advantages of employing the Mediator pattern?
View Answer:
- Singular Responsibility Principle -- You may consolidate the communications between numerous components into a single location, making them easier to understand and maintain.
- The Open/Closed Principle You can add new mediators without changing the key components.
- You can reduce coupling between software components.
- We can use individual components more efficiently.
What are some downsides of the Mediator Pattern?
View Answer:
Drawbacks of the Mediator Pattern.
- A mediator can evolve into a God Object over time.
Are there any alternatives to using the Mediator pattern?
View Answer:
What are the main components of the Mediator Pattern?
View Answer:
Here's an example with comments highlighting the main components.
// Mediator - central communication hub
class ChatRoom {
constructor() {
this.users = {};
}
// Register function acts as the means of adding Colleagues
register(user) {
this.users[user.name] = user;
user.chatRoom = this;
}
// This is where communication between Colleagues happens
send(message, from, to) {
if (to) {
// Single user message
to.receive(message, from);
} else {
// Broadcast message
for (let key in this.users) {
if (this.users[key] !== from) {
this.users[key].receive(message, from);
}
}
}
}
}
// Colleague - the components that are communicating via the Mediator
class User {
constructor(name) {
this.name = name;
this.chatRoom = null; // A reference to the Mediator
}
send(message, to) {
// Interact with the Mediator to send messages
this.chatRoom.send(message, this, to);
}
receive(message, from) {
console.log(`${from.name} to ${this.name}: ${message}`);
}
}
// Creating colleagues
let bob = new User('Bob');
let alice = new User('Alice');
let charlie = new User('Charlie');
// Creating a mediator
let chatroom = new ChatRoom();
// Registering colleagues with the mediator
chatroom.register(bob);
chatroom.register(alice);
chatroom.register(charlie);
// Colleagues interacting with each other via the mediator
bob.send('Hey, Alice', alice);
alice.send('Hi, Bob!', bob);
charlie.send('Hello everyone!');
In this example, ChatRoom
is the Mediator and User
instances (Bob, Alice, Charlie) are Colleagues. The Colleagues communicate with each other via the Mediator (ChatRoom
), which handles and routes messages. This reduces the direct communication paths between the Colleagues, leading to a system that's easier to manage and extend.