scala proxy design pattern with real world example

Proxy Pattern is a structural design pattern which is used to create a representative object that controls access to another object, which may be remote, expensive to create, or in need of securing.

There are many variations of the Proxy Pattern and the variations typically revolve around the way the proxy controls the access. Here are a few ways proxies control access like a remote proxy controls access to a remote object and a virtual proxy controls access to a resource that is expensive to create and a protection proxy controls access to a resource based on access rights so on. The proxy design pattern is good when we want to delegate some expensive operations to other classes, do operations lazily, and thus make our applications more efficient.

Lets check the class diagram for this pattern

The proxy design pattern is another example of a wrapper. First we have a Subject, which provides an interface for the RealSubject and the Proxy. By implementing the same interface, the Proxy can be substituted for the RealSubject anywhere it occurs.The RealSubject is the object that does the real work. It’s the object that the Proxy represents and controls access to. The Proxy holds a reference to the RealSubject. In some cases, the Proxy may be responsible for creating and destroying the RealSubject. Clients interact with the RealSubject through the Proxy. Because the Proxy and RealSubject implement the same interface that is Subject, the Proxy can be substituted anywhere the subject can be used. The Proxy also controls access to the RealSubject; this control may be needed if the Subject is running on a remote machine, if the Subject is expensive to create in some way or if access to the subject needs to be protected in some way.

Lets say we have to access the metric data from oracle db and lets assume this is a static data and we do not want to hit the database each time we need this data in our application. And also we are using a external api to access this data from oracle and the default behaviour is to hit the db every time the data is requested . Considering we have a static data we want to build something which will hit the db only the first time we request for the data and cache it, so that we can return the data from cached data instead of hitting the db each time.

Lets build a proxy to solve this.

First we have a QueryCommand, which provides an interface for the RealSubject and the Proxy. By implementing the same interface, the Proxy can be substituted for the RealSubject anywhere it occurs. We have a real object MetricTableCommand and a proxy for this MetricTableCommandProxy.The MetricTableCommandProxy holds a reference to the MetricTableCommand.

Lets code the QueryCommand


trait QueryCommand[T] {

def execute(parameters:Array[String]):scala.collection.mutable.ListBuffer[T];

}


class MetricTableCommand(dbType: DbType) extends QueryCommand[MetricMetadata] {

def execute(parameters: Array[String]): scala.collection.mutable.ListBuffer[MetricMetadata] =
{
val query: String = "select * from metric_table"

dbType.query(query, parameters, new MetricMetadataMapper())
}

}


class MetricTableCommandProxy() extends QueryCommand[MetricMetadata] {

val command = new MetricTableCommand(new Oracle(new OracleTemplat()))

var array: scala.collection.mutable.ListBuffer[MetricMetadata] = scala.collection.mutable.ListBuffer[MetricMetadata]()

def execute(parameters: Array[String]): scala.collection.mutable.ListBuffer[MetricMetadata] =
{

if (array.size == 0) {
array = command.execute(parameters)
array
} else {
array
}

}

}

Lets code the test class. As we can see client will use the proxy instead of the real object to get the same result.


object Test extends App {

val proxy = new MetricTableCommandProxy
val list = proxy.execute(Array[String]("parameter1"))

}