scala singleton design pattern with realtime example

The Singleton Pattern ensures a class has only one instance, and provides a global point of access to it.There are two ways to create singleton in scala first approach is using scala object and the second approach is using the private constructor with companion object. The recommended approach is using scala object.

Lets say we need to fetch MetricMetaData from one of table and as this data is needed across application and we did not want to have more than one instance of this at any point considering the efficiency and memory constraints.I am not adding the actual sql code as the focus is to show the singleton pattern usage.

First approach Singletons with scala object

With MetricMetaTableCommand defined as an object, there can be only one instance of it, and its methods are called just like static methods on a Java class.


object MetricMetaTableCommand {

private var list: Vector[MetricMetaData] = execute(Array("para1", "para2"))

def getMetricMetaData(): Vector[MetricMetaData] =
{
list
}

private def execute(parameters: Array[String]): Vector[MetricMetaData] =
{
val metricData: Vector[MetricMetaData] = Vector(new MetricMetaData(1, "metric1", "F"));

metricData;
}

}


class MetricMetaData(val id: Int, val metricName: String, metricValueType: String) {

}

Second approach with Private Primary Constructor

To make the primary constructor private we need to use private keyword. An easy way to enforce the singleton in Scala is to make the primary constructor private and put a getInstance method in the companion object of the class. We have a singleton class MetricMetaTableCommand2 with a companion object with the same name which returns the list from getMetricMetaData method.


class MetricMetaTableCommand2 private extends QueryCommand {

override def execute(parameters: Array[String]): Vector[MetricMetaData] =
{

////I am creating a static vector ideally we will have some logic to derive this data

val metricData: Vector[MetricMetaData] = Vector(new MetricMetaData(1, "metric1", "F"));

metricData;
}
}

object MetricMetaTableCommand2 {

var list: Vector[MetricMetaData] = new MetricMetaTableCommand2().execute(Array("para1", "para2"))
def getMetricMetaData(): Vector[MetricMetaData] =
{
list
}

}


trait QueryCommand {
def execute(parameters:Array[String]):Vector[MetricMetaData];
}