The Mediator Design Pattern reduce communication complexity between objects through mediator object. It decouple the direct interaction between objects by providing a
mediator, that facilitates the communication between the objects. Instead of classes communicating directly with each other, classes send messages to the mediator and the mediator sends these messages to the other classes.
When an object wants to communicate with another object(s), it does not interact with other object(s) directly. Instead, it sends its message to the mediator object
whose responsibility is to route the messages to destination object(s).
This pattern is particularly useful in scenarios where a group of objects interact in complex ways and need to be decoupled for better maintainability and extensibility. In this tutorial, we will explore the Mediator Design Pattern in Java. We'll discuss its structure, implementation, and usage. Additionally, we'll delve into best practices for implementing the pattern and highlight its advantages.
Real life Example
- In Air traffic controller. All incoming or outgoing flights don't communicate with each other directly, Instead they communicate with airport's air traffic controller.
- Group chat room. One member of group sends message to chat server, then it is chat server's responsibility to propagate this message to all other members of the group.
Structure of the Factory Design Pattern
- Mediator Interface : Interface used by Colleagues to interact with Mediator.
- Concrete Mediator : Implements Mediator Interface and maintains a list of Colleagues communicating with each other. It facilitates the communication between Colleages by routing their messages to destination colleague(s). It is the communication center for the Colleagues.
- Colleague(s) : Object(s) communicating with other object(s). It contains a reference of Mediator object.
Advantages of Mediator Design Pattern
- Decoupling of Colleagues : One of the primary advantages of the Mediator Design Pattern is the decoupling of colleagues. Colleagues do not have direct references to each other, reducing dependencies and promoting a more modular design.
- Improved Maintainability : The decoupling achieved through the mediator promotes improved maintainability. Changes to one colleague do not require modifications to other colleagues or the mediator, making the system more resilient to changes.
- Centralized Communication : The mediator centralizes communication logic. This centralization simplifies the overall system design by providing a single point of control for coordinating interactions between colleagues.
- Promotion of Reusability : The mediator can be reused in different scenarios. As long as the communication protocol between colleagues remains consistent, the same mediator implementation can be employed in various contexts.
- Easier Extensibility : The Mediator Design Pattern makes the system more extensible. Introducing new colleagues or modifying existing ones is less challenging because changes are localized to the mediator rather than being scattered throughout the system.
- Simplified Communication : Colleagues communicate through the mediator, which simplifies the communication pathways. This simplicity reduces the chances of communication-related bugs and makes it easier to understand and debug the system.
- Promotion of Loose Coupling : Loose coupling is a key benefit of the Mediator Design Pattern. Colleagues only interact with the mediator, and changes to one colleague do not cascade to other colleagues. This loose coupling improves the overall stability of the system.
- Centralized Control : The mediator provides centralized control over the communication flow. This centralized control can be beneficial in scenarios where specific rules or policies need to be enforced during communication between colleagues.
- Support for Complex Systems : The Mediator Design Pattern is particularly useful in complex systems where multiple objects interact in intricate ways. It provides a structured approach to managing these interactions, reducing the complexity of the overall system.
When we should use Mediator Pattern
- When we want to simplify the communication between lots of object interacting with each other.
- When we want to centrally manage all communication between Colleagues.
Implementation of Mediator Design Pattern
Here, we will implement a chat group using mediator pattern. ChatServer is the Mediator interface class that is used by the char participants to interact with mediator object.

public interface ChatServer { public void addUser(Participant user); public void sendMessage(Participant user, String message); }
ChatServerMediator is the concrete implementation of ChatServer interface. It will act as a mediator object, whose primary responsibility is to route messages between participants.
ChatServerMediator.javaimport java.util.List; import java.util.ArrayList; public class ChatServerMediator implements ChatServer { private List<Participant> participantList; public ChatServerMediator(){ participantList = new ArrayList<Participant>(); } public void addUser(Participant user){ participantList.add(user); } public void sendMessage(Participant user, String message){ for(Participant p : participantList){ if(p != user){ p.receiveMessage(message, user); } } } }
Participants is the member of the chat group, communication with each other by calling mediator(ChatServerMediator).
Participant.javapublic class Participant { private String userName; private ChatServer charServerMediator; public Participant(String name){ this.userName = name; } public String getUserName(){ return userName; } public void joinChatGroup(ChatServer chatGroup){ charServerMediator = chatGroup; charServerMediator.addUser(this); } public void sendMessage(String message){ System.out.println(userName +", Sending this message : \"" + message + "\""); charServerMediator.sendMessage(this, message); } public void receiveMessage(String message, Participant user){ System.out.println(userName + ", Received : \"" + message + "\", From : " + user.userName); } }
MediatorPatternExample will simulate the communication between participants using ChatServerMediator.
MediatorPatternExample.javapublic class MediatorPatternExample { public static void main (String args[]){ ChatServer chatServer = new ChatServerMediator(); Participant jack = new Participant("Jack"); Participant george = new Participant("George"); Participant emilly = new Participant("Emilly"); jack.joinChatGroup(chatServer); george.joinChatGroup(chatServer); emilly.joinChatGroup(chatServer); // Jack is sending message jack.sendMessage("Hi Everyone, I am Jack"); // Emilly replying to Jack emilly.sendMessage("Hi Jack, How are you"); } }
Output
Jack, Sending this message : "Hi Everyone, I am Jack" George, Received : "Hi Everyone, I am Jack", From : Jack Emilly, Received : "Hi Everyone, I am Jack", From : Jack Emilly, Sending this message : "Hi Jack, How are you" Jack, Received : "Hi Jack, How are you", From : Emilly George, Received : "Hi Jack, How are you", From : Emilly
Best Practices of Mediator Design Pattern
- Design the mediator interface with a clear and concise set of methods for communication between colleagues. Avoid adding unnecessary methods that may lead to a bloated interface.
- Colleagues should not be aware of each other's existence. They communicate through the mediator, and changes to one colleague should not impact others. This independence simplifies maintenance and extensibility.
- The mediator should encapsulate the communication logic between colleagues. Colleagues should not have direct references to each other, promoting loose coupling and independence.
- If the mediator needs to maintain state information, manage it carefully to avoid becoming a monolithic controller. Consider using a separate state manager or delegating state management to the colleagues when appropriate.
- Define interfaces for colleagues to ensure a consistent communication protocol. Concrete colleagues implement these interfaces, and the mediator works with the interfaces rather than concrete implementations.
- Design the mediator to be reusable across different scenarios. Avoid hard-coding specific colleague interactions, making the mediator adaptable to different contexts.
- Avoid creating a "God" mediator that handles all interactions in the system. Instead, consider creating multiple mediators with specific responsibilities, promoting a more modular and maintainable design.
- Define a consistent approach to error handling in the mediator. Decide whether errors during communication should be handled centrally in the mediator or whether individual colleagues should handle errors.
- Use clear and meaningful names for mediator methods and colleagues. Naming conventions such as sendMessage and receiveMessage provide clarity regarding the purpose of the methods.
- Document the mediator-related classes and methods. Clearly specify the responsibilities of the mediator, colleagues, and any other related components. Provide examples or documentation on how to extend or modify the mediator for different scenarios.
Memento Design Pattern |
Bridge Design Pattern |
Interpreter Design Pattern |
Facade Design Pattern |
Observer Design Pattern |
List of Design Patterns |