scala builder pattern real world example using the named and default parameters feature

The builder pattern is an object creation software design pattern. The intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern that occurs when the increase of object constructor parameter combination leads to an exponential list of constructors. Instead of using numerous constructors, the builder pattern uses another object, a builder, that receives each initialization parameter step by step and then returns the resulting constructed object at once.

Lets take an example consider the case of a class representing a alert which occurs when there is some issue in the network and based on the source of the alert the parameters that will be received varies drastically . Lets say if the alert is from a array we get somewhere around 9 properties and an alert from the switch will have only 4 parameters.What sort of constructors or static factories should you write for such a class. In these scenarios we use the telescoping constructor pattern, in
which we provide a constructor with only the required parameters, another with a single optional parameter, a third with two optional parameters and so on.

Check the same pattern implemented in java for better understanding of what we are trying to achieve here builder-pattern-real-world-example-java

From Scala 2.8 with support for named and default parameters have got the ability to replace builder pattern we will be demonstrating the same in this article.

In scala we can use both named arguments and default arguments in methods and we will be using this feature.In the below method we have set a default value for all the parameters except for subElementId,metricMetadataId and metricMetadataHourlyId as these three are mandatory parameters.


def build(subElementId:Int, metricMetadataId:Int, metricMetadataHourlyId:Int,
metricValue: Option[Int] = Some(0), createdTimestamp: Option[String] = Some(""), meanDeviation: Option[Int] = Some(0),
thresold: Option[Int] = Some(0), durationType: Option[String]= Some(""), durationInterval: Option[Int] = Some(0)):Alert =
{

this.subElementId=subElementId;
this.metricMetadataId=metricMetadataId;
this.metricMetadataHourlyId=metricMetadataHourlyId;
this.metricValue=metricValue;
this.createdTimestamp=createdTimestamp;
this.meanDeviation=meanDeviation;
this.thresold=thresold;
this.durationType=durationType;
this.durationInterval=durationInterval;
this;

}

So using the above method we can construct the object just the way we do using the builder pattern as below

val alert2: Alert = new Alert().build(subElementId = 1000, metricMetadataId = 2000, metricMetadataHourlyId = 3000, metricValue = Some(45));

Below is the full code


class Alert() {

var subElementId:Int=0
var metricMetadataId:Int=0
var metricMetadataHourlyId:Int=0
var metricValue = None: Option[Int]
var createdTimestamp = None: Option[String]
var meanDeviation = None: Option[Int]
var thresold = None: Option[Int]
var durationType = None: Option[String]
var durationInterval = None: Option[Int]

def build(subElementId:Int, metricMetadataId:Int, metricMetadataHourlyId:Int,
metricValue: Option[Int] = Some(0), createdTimestamp: Option[String] = Some(""), meanDeviation: Option[Int] = Some(0),
thresold: Option[Int] = Some(0), durationType: Option[String]= Some(""), durationInterval: Option[Int] = Some(0)):Alert =
{

this.subElementId=subElementId;
this.metricMetadataId=metricMetadataId;
this.metricMetadataHourlyId=metricMetadataHourlyId;
this.metricValue=metricValue;
this.createdTimestamp=createdTimestamp;
this.meanDeviation=meanDeviation;
this.thresold=thresold;
this.durationType=durationType;
this.durationInterval=durationInterval;
this;

}
}

Driver code to test


object Driver {

def main(args: Array[String]): Unit = {

val alert1: Alert = new Alert().build(subElementId = 1000, metricMetadataId = 2000, metricMetadataHourlyId = 3000);

val alert2: Alert = new Alert().build(subElementId = 1000, metricMetadataId = 2000, metricMetadataHourlyId = 3000, metricValue = Some(45));

}

}