Mediator Design Pattern

According to GoF definition, mediator pattern defines 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 us vary their interaction independently.

Mediator is a behavioral design pattern and one of other 23 patterns discussed by GoF.

1. When to use mediator design pattern

Mediator helps in establishing loosely coupled communication between objects and helps in reducing the direct references to each other. This helps in minimizing the complexity of dependency management and communications among participating objects.

Mediator helps to facilitate the interaction between objects in a manner in that objects are not aware of the existence of other objects. Objects depend only on a single mediator class instead of being coupled to dozens of other objects.

During designing a solution to a problem, if you encounter a situation where multiple objects need to interact with each other to process the request, but direct communication may create a complex system, you can consider using mediator pattern.

The pattern lets you extract all the relationships between classes into a separate class, isolating any changes to a specific component from the rest of the components.

2. Real world example of mediator pattern

  • A great real world example of mediator pattern is traffic control room at airports. If all flights will have to interact with each other for finding which flight is going to land next, it will create a big mess.

    Rather flights only send their status to the tower. These towers in turn send the signals to conform which airplane can take-off or land. We must note that these towers do not control the whole flight. They only enforce constraints in the terminal areas.

  • Another good example of mediator pattern is a chat application. In a chat application we can have several participants. It’s not a good idea to connect each participant to all the others because the number of connections would be really high. The best solution is to have a hub where all participants will connect; this hub is just the mediator class.
  • In Java programming, the execute() method inside the java.util.concurrent.Executor interface follows this pattern. The different overloaded versions of various schedule() methods of the java.util.Timer class also can be considered to follow this pattern.

3. Mediator design pattern

This pattern defines a separate (mediator) object that encapsulates the interaction between a set of objects and the objects delegate their interaction to a mediator object instead of interacting with each other directly.

3.1. Architecture

Mediator design pattern
Mediator design pattern

Image Credit – Wikipedia

3.2. Design participants

  • Mediator – defines the interface for communication between Colleague objects
  • ConcreteMediator – implements the Mediator interface and coordinates communication between Colleague objects. It is aware of all of the Colleagues and their purposes with regards to inter-communication.
  • Colleague – defines the interface for communication with other Colleagues through its Mediator
  • ConcreteColleague – implements the Colleague interface and communicates with other Colleagues through its Mediator

4. Mediator design pattern example

In this Java mediator pattern example, we are simulating the chat application where users can send messages to other users in one to one fashion. All users must be registered to the chat application to send or receive messages.

Mediator Interface

public interface IChatRoom 
{
    public void sendMessage(String msg, String userId);

    void addUser(User user);
}

Concrete Mediator

import java.util.HashMap;
import java.util.Map;

public class ChatRoom implements IChatRoom {

    private Map<String, User> usersMap = new HashMap<>();

    @Override
    public void sendMessage(String msg, String userId) 
    {
        User u = usersMap.get(userId);
        u.receive(msg);
    }

    @Override
    public void addUser(User user) {
        this.usersMap.put(user.getId(), user);
    }
}

Colleague Class

public abstract class User
{
    private IChatRoom mediator;
    
    private String id;
    private String name;
    
    public User(IChatRoom room, String id, String name){
        this.mediator = room;
        this.name = name;
        this.id = id;
    }
    
    public abstract void send(String msg, String userId);
    public abstract void receive(String msg);

    public IChatRoom getMediator() {
        return mediator;
    }

    public String getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}

Concrete Colleagues

public class ChatUser extends User {
    
    public ChatUser(IChatRoom room, String id, String name) {
        super(room, id, name);
    }

    @Override
    public void send(String msg, String userId) {
        System.out.println(this.getName() + " :: Sending Message : " + msg);
        getMediator().sendMessage(msg, userId);
    }

    @Override
    public void receive(String msg) {
        System.out.println(this.getName() + " :: Received Message : " + msg);
    }

}

Test the mediator pattern.

public class Main 
{
    public static void main(String[] args) 
    {
        IChatRoom chatroom = new ChatRoom();
        
        User user1 = new ChatUser(chatroom,"1", "Alex");
        User user2 = new ChatUser(chatroom,"2", "Brian");
        User user3 = new ChatUser(chatroom,"3", "Charles");
        User user4 = new ChatUser(chatroom,"4", "David");
        
        chatroom.addUser(user1);
        chatroom.addUser(user2);
        chatroom.addUser(user3);
        chatroom.addUser(user4);

        user1.send("Hello brian", "2");
        user2.send("Hey buddy", "1");
    }
}

Program output.

Alex :: Sending Message : Hello brian
Brian :: Received Message : Hello brian

Brian :: Sending Message : Hey buddy
Alex :: Received Message : Hey buddy

5. FAQs

  • Benefits of mediator pattern

    Using mediator pattern, we can reduce the complexity of communication between objects in a system. It promotes loose coupling and reduces number of subclasses in the system.

    Mediator helps in replacing “many-to-many” relationship with “one-to-many” relationships, so it is much easier to read and understand. Also the maintenance becomes easy due to centralized control of communication.

  • Drawbacks of mediator pattern

    The mediator object’s architecture may become complex if you put too much logic inside it. An inappropriate use of the mediator pattern may end up with a “God Class” anti-pattern.

  • Mediator pattern vs facade pattern

    Mediator pattern can be seen as a multiplexed facade pattern. In mediator, instead of working with an interface of a single object, you are making a multiplexed interface among multiple objects to provide smooth transitions.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.