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
trait Alert { def alertType:String }
class DynamicAlert(var elementId:Int,var metricMetadataId:Int,var metricMetadataHourlyId:Int,var durationType:String,var durationInterval:Int,var alertType:String) extends Alert { }
class ThresholdAlert(var elementId:Int,var metricMetadataId:Int,var metricMetadataHourlyId:Int,var durationType:String,var durationInterval:Int,var alertType:String) extends Alert { }
Lets code the AlertObserver hierarchy
trait AlertObserver { def publish(alert: Alert): Unit; }
class FileAlertSubscriber() extends AlertObserver { def publish(alert: Alert): Unit= { println("FileAlertSubscriber called") // logges the breach into a file for further analysys } }
class OracleAlertSubscriber() extends AlertObserver { def publish(alert: Alert): Unit= { // insert alert into oracle for further analyses println("OracleAlertSubscriber called") } }
class HaasAlertSubscriber() extends AlertObserver { def publish(alert: Alert): Unit= { println("HaasAlertSubscriber called") // logges the breach into a file for further analysys } }
Lets code the mediator hierarchy
trait IAlertMediator { def addSubscriberToDynamicAlert(alertobserver:AlertObserver) def addSubscriberToThresholdAlert(alertobserver:AlertObserver) def publishAlert(alert:Alert) }
class AlertMediator extends IAlertMediator { val thresoldAlertToObserver: scala.collection.mutable.Map[String, scala.collection.mutable.ListBuffer[AlertObserver]] = scala.collection.mutable.Map[String, scala.collection.mutable.ListBuffer[AlertObserver]]() val dynamicAlertToObserver: scala.collection.mutable.Map[String, scala.collection.mutable.ListBuffer[AlertObserver]] = scala.collection.mutable.Map[String, scala.collection.mutable.ListBuffer[AlertObserver]]() def addSubscriberToDynamicAlert(alertobserver: AlertObserver) = { var list: Option[scala.collection.mutable.ListBuffer[AlertObserver]] = dynamicAlertToObserver.get("dynamic") if (list == None) { list = Some(scala.collection.mutable.ListBuffer[AlertObserver]()) dynamicAlertToObserver.put("dynamic", list.getOrElse(null)) } list.getOrElse(null) += alertobserver } def addSubscriberToThresholdAlert(alertobserver: AlertObserver) = { var list: Option[scala.collection.mutable.ListBuffer[AlertObserver]] = thresoldAlertToObserver.get("threshold") if (list == None) { list = Some(scala.collection.mutable.ListBuffer[AlertObserver]()) thresoldAlertToObserver.put("threshold", list.getOrElse(null)) } list.getOrElse(null) += alertobserver } def publishAlert(alert: Alert) = { if (alert.alertType == "dynamic") { for ((k, v) <- dynamicAlertToObserver) { v.foreach { e => e.publish(alert); } } } else if (alert.alertType == "threshold") { for ((k, v) <- thresoldAlertToObserver) { v.foreach { e => e.publish(alert); } } } } }
Finally lets code the test class
object Driver extends App { val alertMediator: IAlertMediator = new AlertMediator() val file: AlertObserver = new FileAlertSubscriber() val oracle: AlertObserver = new OracleAlertSubscriber() val haas: AlertObserver = new HaasAlertSubscriber() alertMediator.addSubscriberToDynamicAlert(file) alertMediator.addSubscriberToDynamicAlert(oracle) alertMediator.addSubscriberToThresholdAlert(haas) val dynamicAlert: DynamicAlert = new DynamicAlert(100, 200, 300, "PW", 5, "dynamic") val thresholdAlert: ThresholdAlert = new ThresholdAlert(100, 200, 300, "PW", 5, "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.
likes the example
Hi Adarsh,
Thanks for your wonderful and useful website.
I need your help to get quickly start in Hadoop and Spark based project.
As I am speeding up in Scala and I have decent knowledge in core java and java framework.
Many thanks in advance !!
Regards
Abhishek