Mediator Design Pattern

Intent

Define 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 you vary their interaction independently.

Explanation

Mediator design pattern is very helpful in an enterprise application where multiple objects are interacting with each other. If the objects interact with each other directly, the system components are tightly-coupled with each other that makes maintainability cost higher and not flexible to extend easily. Mediator pattern focuses on to provide a mediator between objects for communication and help in implementing lose-coupling between objects.

Air traffic controller is a great example of mediator pattern where the airport control room works as a mediator for communication between different flights. Mediator works as a router between objects and it can have it’s own logic to provide a way of communication.

Structure

Participants

1. Mediator 
  • This component defines an interface for communicating with Colleague objects.
2. ConcreteMediator 
  • This component implements cooperative behavior by coordinating Colleague objects.
  • It knows and maintains its colleagues.
3. Colleague classes
  • Each Colleague class knows its Mediator object.
  • Each colleague communicates with its mediator whenever it would have otherwise communicated with another colleague.

Source code

Here we'll use the Mediator pattern in the context of a chatroom application. First, we'll define an interface for our mediator.
//Mediator interface
public interface Mediator {
  public void send(String message, Colleague colleague);
}
While we described the Colleague as an interface above, it's more useful to use an abstract class in this case:
//Colleage interface
public abstract Colleague{
  private Mediator mediator;
  public Colleague(Mediator m) {
    mediator = m;
  }
  //send a message via the mediator
  public void send(String message) {
    mediator.send(message, this);
  }
  //get access to the mediator
  public Mediator getMediator() {return mediator;}
  public abstract void receive(String message);
}
Now let's create our concrete mediator implementation
public class ApplicationMediator implements Mediator {
  private ArrayList<Colleague> colleagues;
  public ApplicationMediator() {
    colleagues = new ArrayList<Colleague>();
  }
  public void addColleague(Colleague colleague) {
    colleagues.add(colleague);
  }
  public void send(String message, Colleague originator) {
    //let all other screens know that this screen has changed
    for(Colleague colleague: colleagues) {
      //don't tell ourselves
      if(colleague != originator) {
        colleage.receive(message);
      }
    }
  }
}
Finally, we'll create one concrete colleague. 

public class ConcreteColleague extends Colleague {
  public void receive(String message) {
    System.out.println("Colleague Received: " + message);
  }
}
If we assume that we could have many different colleagues that react differently when a message is received, this pattern fits in well. For example, we could have a mobileColleague that needs to display the message differently to the desktop colleague.
public class MobileColleague extends Colleague {
  public void receive(String message) {
    System.out.println("Mobile Received: " + message);
  }
}
Here's a client that drives the entire application: 
public class Client {
  public static void main(String[] args) {
    ApplicationMediator mediator = new ApplicationMediator();
    ConcreteColleague desktop = new ConcreteColleague(mediator);
    ConcreteColleague mobile = new MobileColleague(mediator);
    mediator.addColleague(desktop);
    mediator.addColleague(mobile);
    desktop.send("Hello World");
    mobile.send("Hello");
  }
}

Important Points

  • Mediator pattern is useful when the communication logic between objects is complex, we can have a central point of communication that takes care of communication logic.
  • Java Message Service (JMS) uses Mediator pattern along with Observer pattern to allow applications to subscribe and publish data to other applications.
  • We should not use mediator pattern just to achieve lose-coupling because if the number of mediators will grow, then it will become hard to maintain them.

Applicability

Use the Mediator pattern when
  • a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand
  • reusing an object is difficult because it refers to and communicates with many other objects
  • a behavior that's distributed among several classes should be customizable without a lot of subclassing

Real world examples

Related Patterns


Credits

Comments