mediator design pattern real world example in java

Mediator is a behavioral design pattern which helps in decoupling classes which communicate with each other in some way in order to accomplish some specific functionality. The mediator design pattern defines an mediator object that encapsulates how a set of other objects interact with each other in order to promote loose coupling which will allow us to vary class interactions independently and also it will help us to design decoupled and reusable classes.

Mediator pattern is useful in cases where we have many-to-many relationships between interacting objects. Though there are some similarities between the observer and the mediator pattern the observer pattern is used when we have one to many relationships where as mediator is used when we have many-to-many relationships.

Lets take an example we had two modules in our application which would detect breaches based on the historical pattern which is called dynamic alert and another module which would detect alert on a static threshold value. Multiple components where interested to know when ever there is a breach in the network . Few of the interested components where analytics algorithms, oracle component, file based readers and many more. And some components where interested in dynamic alerts and others where on threshold alerts and few on both . So we have many-to-many relationship here between the alerts and the subscribers . One type of alert is subscribed by many subscribers and one subscribers is interested in many types of alerts. We will solve this many to many relationships problem by using the mediator design pattern.

Lets code the alert hierarchy


public interface Alert {

public String getAlertType();

}


public class DynamicAlert implements Alert {

private int subElementId;
private int metricMetadataId;
private int metricMetadataHourlyId;
private float metricValue;
private String alertType;

public DynamicAlert(int subElementId, int metricMetadataId, int metricMetadataHourlyId, float metricValue,
List<Integer> elementsEffected, String alertType) {
super();
this.subElementId = subElementId;
this.metricMetadataId = metricMetadataId;
this.metricMetadataHourlyId = metricMetadataHourlyId;
this.metricValue = metricValue;
this.alertType = alertType;
}

public String getAlertType() {
return alertType;
}

public void setAlertType(String alertType) {
this.alertType = alertType;
}

public int getSubElementId() {
return subElementId;
}

public void setSubElementId(int subElementId) {
this.subElementId = subElementId;
}

public int getMetricMetadataId() {
return metricMetadataId;
}

public void setMetricMetadataId(int metricMetadataId) {
this.metricMetadataId = metricMetadataId;
}

public int getMetricMetadataHourlyId() {
return metricMetadataHourlyId;
}

public void setMetricMetadataHourlyId(int metricMetadataHourlyId) {
this.metricMetadataHourlyId = metricMetadataHourlyId;
}

public float getMetricValue() {
return metricValue;
}

public void setMetricValue(float metricValue) {
this.metricValue = metricValue;
}

}

public class ThresholdAlert implements Alert{

private int elementId;
private int metricMetadataId;
private int metricMetadataHourlyId;
private float metricValue;
private String alertType;

public ThresholdAlert(int subElementId, int metricMetadataId, int metricMetadataHourlyId, float metricValue,
List<Integer> elementsEffected, String alertType) {
super();
this.elementId = subElementId;
this.metricMetadataId = metricMetadataId;
this.metricMetadataHourlyId = metricMetadataHourlyId;
this.metricValue = metricValue;
this.alertType = alertType;
}

public int getElementId() {
return elementId;
}

public void setElementId(int elementId) {
this.elementId = elementId;
}

public String getAlertType() {
return alertType;
}

public void setAlertType(String alertType) {
this.alertType = alertType;
}

public int getSubElementId() {
return elementId;
}

public void setSubElementId(int subElementId) {
this.elementId = subElementId;
}

public int getMetricMetadataId() {
return metricMetadataId;
}

public void setMetricMetadataId(int metricMetadataId) {
this.metricMetadataId = metricMetadataId;
}

public int getMetricMetadataHourlyId() {
return metricMetadataHourlyId;
}

public void setMetricMetadataHourlyId(int metricMetadataHourlyId) {
this.metricMetadataHourlyId = metricMetadataHourlyId;
}

public float getMetricValue() {
return metricValue;
}

public void setMetricValue(float metricValue) {
this.metricValue = metricValue;
}

}

Lets code the AlertObserver hierarchy


public interface AlertObserver {

public void publish(Alert alert);
}


public class FileAlertSubscriber implements AlertObserver {

@Override
public void publish(Alert alert) {

System.out.println("Alert recieved in filealertsubscriber");

}
}


public class OracleAlertSubscriber implements AlertObserver {

@Override
public void publish(Alert alert) {
System.out.println("Alert recieved in OracleAlertSubscriber");
}

}

 


public class HaasAlertSubscriber implements AlertObserver {

@Override
public void publish(Alert alert) {
System.out.println("Alert recieved in HaasAlertSubscriber");
}

}

Lets code the mediator hierarchy


public interface IAlertMediator {

public void addSubscriberToDynamicAlert(AlertObserver alertobserver);

public void addSubscriberToThresholdAlert(AlertObserver alertobserver);

public void publishAlert(Alert alert);

}


public class AlertMediator implements IAlertMediator {

private Map<String, List<AlertObserver>> thresoldAlertToObserver = new HashMap<String, List<AlertObserver>>();

private Map<String, List<AlertObserver>> dynamicAlertToObserver = new HashMap<String, List<AlertObserver>>();

@Override
public void addSubscriberToDynamicAlert(AlertObserver alertobserver) {
// TODO Auto-generated method stub

List<AlertObserver> list = dynamicAlertToObserver.get("dynamic");

if (list == null) {
list = new ArrayList<AlertObserver>();
dynamicAlertToObserver.put("dynamic", list);
}

list.add(alertobserver);

}

@Override
public void addSubscriberToThresholdAlert(AlertObserver alertobserver) {

List<AlertObserver> list = thresoldAlertToObserver.get("threshold");

if (list == null) {
list = new ArrayList<AlertObserver>();
thresoldAlertToObserver.put("threshold", list);
}

list.add(alertobserver);

}

public void publishAlert(Alert alert) {
if (alert.getAlertType().equalsIgnoreCase("dynamic")) {
for (Map.Entry<String, List<AlertObserver>> pair : dynamicAlertToObserver.entrySet()) {

for (AlertObserver alertObserver : pair.getValue()) {

alertObserver.publish(alert);

}

}

} else if (alert.getAlertType().equalsIgnoreCase("threshold")) {
for (Map.Entry<String, List<AlertObserver>> pair : thresoldAlertToObserver.entrySet()) {

for (AlertObserver alertObserver : pair.getValue()) {

alertObserver.publish(alert);

}

}

}

}

}

Finally lets code the test class


public class Test {

public static void main(String[] args) {

IAlertMediator alertMediator = new AlertMediator();

AlertObserver file = new FileAlertSubscriber();

AlertObserver oracle = new OracleAlertSubscriber();

AlertObserver haas = new HaasAlertSubscriber();

alertMediator.addSubscriberToDynamicAlert(file);
alertMediator.addSubscriberToDynamicAlert(oracle);
alertMediator.addSubscriberToThresholdAlert(haas);

Alert dynamicAlert = new DynamicAlert(100, 200, 300, 22.45f, new ArrayList<Integer>(new Integer(1)), "dynamic");

Alert thresholdAlert = new ThresholdAlert(100, 200, 300, 22.45f, new ArrayList<Integer>(new Integer(1)),
"threshold");

alertMediator.publishAlert(dynamicAlert);

alertMediator.publishAlert(thresholdAlert);

}

}

 

As we can see in the example above we are able to decouple the alert classes completely from the subscriber and adding a new subscriber or removing a subscriber is straight forward . Also as there is no dependency between object its easier to modify the classes.