Behavioral Design Patterns provide solution for the better interaction between objects and how to provide lose coupling and flexibility to extend easily. Following design patterns come under this category.
Mediator pattern adds a third party object (called mediator) to control the interaction between two objects (called colleagues). It helps reduce the coupling between the classes communicating with each other.
Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Mediator design pattern is used to provide a centralized communication medium between different objects in a system. Rather than interacting directly with each other, objects ask the Mediator to interact on their behalf which results in reusability and loose coupling. It encapsulates the interaction between the objects and makes them independent from each other. This allows them to vary their interaction with other objects in a totally different way by implementing a different mediator.
The Mediator helps to reduce the complexity of the classes. Each object no longer has to know in detail about how to interact with the other objects.
When to use the Mediator Pattern
The participants classes in this pattern are:
For our example, we will try to implement a chat application where users can do group chat. Every user will be identified by it’s name and they can send and receive messages. The message sent by any user should be received by all the other users in the group.
Java
First of all we will create Mediator
interface that will define the contract for concrete mediators.
File ChatMediator.java.
public interface ChatMediator { public void sendMessage(String msg, User user); void addUser(User user); }
Users can send and receive messages, so we can have User
interface or abstract class. I am creating User
as abstract class like below.
File User.java
public abstract class User { protected ChatMediator mediator; protected String name; public User(ChatMediator med, String name){ this.mediator = med; this.name = name; } public abstract void send(String msg); public abstract void receive(String msg); }
Notice that User
has a reference to the mediator object, it’s required for the communication between different users.
Now we will create ConcreteMediator class, it will have a list of users in the group and provide logic for the communication between the users.
File ChatMediatorImpl.java.
public class ChatMediatorImpl implements ChatMediator { private List<User> users; public ChatMediatorImpl(){ this.users = new ArrayList<>(); } @Override public void addUser(User user){ this.users.add(user); } @Override public void sendMessage(String msg, User user) { for(User u : this.users){ //message should not be received by the user sending it if(u != user){ u.receive(msg); } } } }
Now we can create concrete User
classes to be used by client system.
File UserImpl.java
public class UserImpl extends User { public UserImpl(ChatMediator med, String name) { super(med, name); } @Override public void send(String msg){ System.out.println(this.name+": Sending Message: "+msg); mediator.sendMessage(msg, this); } @Override public void receive(String msg) { System.out.println(this.name+": Received Message: "+msg); } }
Notice that send()
method is using mediator to send the message to the users and it has no idea how it will be handled by the mediator.
Let’s test this our chat application with a simple program where we will create mediator and add users to the group and one of the user will send a message.
File ChatClient.java.
public class ChatClient { public static void main(String[] args) { ChatMediator mediator = new ChatMediatorImpl(); User user1 = new UserImpl(mediator, "John"); User user2 = new UserImpl(mediator, "Lisa"); User user3 = new UserImpl(mediator, "Maria"); User user4 = new UserImpl(mediator, "David"); mediator.addUser(user1); mediator.addUser(user2); mediator.addUser(user3); mediator.addUser(user4); user1.send("Hi All"); } }
Notice that client program is very simple and it has no idea how the message is getting handled and if mediator is getting user or not.
Python 3
import abc class User(metaclass=abc.ABCMeta): def __init__(self, med, name): self.mediator = med self.name = name @abc.abstractmethod def send(self, msg): pass @abc.abstractmethod def receive(self, msg): pass class ChatMediatorImpl: def __init__(self): self.users = [] def add_user(self, user): self.users.append(user) def send_message(self, msg, user): for u in self.users: if u != user: u.receive(msg) class UserImpl(User): def send(self, msg): print(self.name + ": Sending Message: " + msg) self.mediator.send_message(msg, self) def receive(self, msg): print(self.name + ": Received Message: " + msg) if __name__ == '__main__': mediator = ChatMediatorImpl() user1 = UserImpl(mediator, "John") user2 = UserImpl(mediator, "Lisa") user3 = UserImpl(mediator, "Maria") user4 = UserImpl(mediator, "David") mediator.add_user(user1) mediator.add_user(user2) mediator.add_user(user3) mediator.add_user(user4) user1.send("Hi All")