facade pattern scala with real world example

The Facade Pattern provides a unified interface to a set of interfaces in a subsytem. Facade defines a higher-level interface that makes the subsystem easier to use.

The Facade Pattern allows us to avoid tight coupling between clients and subsystems and also it helps us adhere to a object oriented principle called Principle of Least Knowledge – talk only to your immediate friends.This principle prevents us from creating designs that have a large number of classes coupled together so that changes in one part of the system cascade to other parts. When you build a lot of dependencies between many classes, you are building a fragile system that will be costly to maintain and complex for others to understand.

Using facade pattern the clients will just interact and depend on just one class which will be our facade class instead of depending on many classes.

Lets take an example in one of our project we had written an api for handling breach journey. Once the system finds out that there is a breach in elements the system will use our breach journey api to validate and pass the breach to the required downstream interfaces.

As part of the breach processing many steps where performed like enriching the breach data,validating the breach data for duplication and then passing on the breach data to the interested components.Lets see the client code without using facade first


object Test {

def run(breach: Breach): Unit =
{

val data: EnrichElementData = EnrichElementData.getEnrichData(100);
val test: Boolean = new BreachValidator().isDuplicate(breach.elementId);
if (!test) {
new FileAlertSubscriber().publish(breach, data);
}

}

}

Lets write a facade to provide a unified interface which will make the usage of api by subsystem easier to use.


class BreachJourneyFacade(breachValidator: BreachValidator, breachObserver: BreachObserver) {

def breachJourney(breach: Breach): Unit =
{
val data: EnrichElementData = EnrichElementData.getEnrichData(100);
val test = breachValidator.isDuplicate(breach.elementId)
if (!test) {
breachObserver.publish(breach, data);
}

}

}

With the facade in place the client code is much easier to use


object TestWithFacade {

def breachProcessor(breach: Breach): Unit =
{
new BreachJourneyFacade(new BreachValidator(), new FileAlertSubscriber()).breachJourney(breach);
}

}

 

Domain object used above


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


trait BreachObserver {

def publish(alert: Breach, enrich: EnrichElementData): Unit;

}

class BreachValidator {

def isDuplicate(card_id: Int): Boolean =
{
// logic to determine whether a breach was already generated in the last
// polling cycle so that we can supress this breach
true;
}

}

class EnrichElementData(var subelement_name: String, var element_name: String, var element_vendor: String) {

}

object EnrichElementData {
def getEnrichData(element_id: Int): EnrichElementData =
{
//Logic to derive the element properties required from element_id

new EnrichElementData("element_name", "element_name", "element_vendor");
}
}

class FileAlertSubscriber extends BreachObserver {

def publish(alert: Breach, enrich: EnrichElementData): Unit=
{
// logges the breach into a file for further analysys
}

}