scala observer design pattern real world example in scala

The observer pattern is part of the behavioural design pattern and it defines a one-to-many dependency between objects so that when one object changes state all of its dependents are notified and updated automatically. The observer design pattern is easy to implement and allows us to add new observers or remove old observers at runtime.

Lets take an example we had application which would detect breaches based on the historical pattern and 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 and also the data was published to a messaging queue to name a few. This is a kind of use case the observer pattern is made for and we will implement the same here.

In observer pattern the subject is the interface which will be used to by the objects to register and de register as the observers.All observers need to implement a observer interface and this interface will usually have one method like publish which will be called by the subject when there is a change in the subject state.

Below is the class diagram we will be working on

Lets code this example

Subject Code

Here AlertObservable is our subject trait which has methods to register,unregister and to notifyObservers when there is a change in the state of the object being observed.


trait AlertObservable {

def register(observer: AlertObserver): Unit;

def unregister(observer: AlertObserver): Unit;

def notifyObservers(alert: Alert): Unit;

}

PublishAlert is our concrete AlertObservable which is composed of a list of alertObserver which will be updated when there is a new observer is added or existing observer is unregistered . The constructor has been declared private to make this class a singleton and also an companion object is created to get the sole instance of this object. When there is a an alert the publish method iterates through the alertObservers list and published the alert into all the observers.


import scala.collection.mutable.ArrayBuffer

class PublishAlert private extends AlertObservable {

val observerList: ArrayBuffer[AlertObserver] = ArrayBuffer[AlertObserver]();

def register(observer: AlertObserver): Unit =
{

observerList += observer;

}

def unregister(observer: AlertObserver): Unit =
{

val index: Int = observerList.indexOf(observer)
observerList.remove(index)

}

def notifyObservers(alert: Alert): Unit =
{

observerList.foreach {

observer =>
observer.publish(alert);

}

}
}

object PublishAlert
{

val pubalert:PublishAlert=new PublishAlert

def getInstance():PublishAlert =
{
pubalert
}

}

Observer Code

AlertObserver is our observer trait which just have one method to publish the alert into all the observers.


trait AlertObserver {

def publish(alert: Alert): Unit;

}

Concrete alert observers FileAlertSubscriber and OracleAlertSubscriber . I have not added any implementation into the publish method ideally you should have the logic to insert data into the oracle database in the OracleAlertSubscriber and logging into the file in the FileAlertSubscriber.


class FileAlertSubscriber(observable:AlertObservable) extends AlertObserver {

observable.register(this);

def publish(alert: Alert): Unit=
{
println("FileAlertSubscriber called")

// logges the breach into a file for further analysys
}

}


class OracleAlertSubscriber(observable:AlertObservable) extends AlertObserver {

observable.register(this);

def publish(alert: Alert): Unit=
{
// insert alert into oracle for further analyses

println("OracleAlertSubscriber called")
}

}

Alert domain object

class Alert(var elementId:Int,var metricMetadataId:Int,var metricMetadataHourlyId:Int,var durationType:String,var durationInterval:Int) {

}

When we detect any alert we should get the common alertObservable which was used when constructing all our observers and notify them as below.


object Test extends App{

val fileObserver:FileAlertSubscriber= new FileAlertSubscriber(PublishAlert.getInstance)

val oracleObserver:OracleAlertSubscriber= new OracleAlertSubscriber(PublishAlert.getInstance)

PublishAlert.getInstance.notifyObservers(new Alert(1,2,3,"value",4))

}