Search code examples
scalafactorycompanion-object

Factory with companion object where each type of object takes a common parameter


I have a class like this -

class Cache (
  tableName: String,
  TTL: Int) {
  // Creates a cache
}

I have a companion object that returns different types of caches. It has functions that require a base table name and can construct the cache.

object Cache {
   def getOpsCache(baseTableName: String): Cache = {
    new Cache(s"baseTableName_ops", OpsTTL);
  }

  def getSnapshotCache(baseTableName: String): Cache = {
    new Cache(s"baseTableName_snaps", SnapshotTTL);
  }

  def getMetadataCache(baseTableName: String): Cache = {
    new Cache(s"baseTableName_metadata", MetadataTTL);
  }
}

The object does a few more things and the Cache class has more parameters, which makes it useful to have a companion object to create different types of Caches. The baseTableName parameter is same for all of the caches. Is there a way in which I can pass this parameter only once and then just call the functions to get different types of caches ?

Alternative to this is to create a factory class and pass the baseTableName parameter to constructor and then call the functions. But I am wondering if it could be done in any way with the Companion object.


Solution

  • The simplest way is to put your factory in a case class:

    case class CacheFactory(baseTableName: String) {
    
      lazy val getOpsCache: Cache = 
         Cache(s"baseTableName_ops", OpsTTL)
    
      lazy val getSnapshotCache =
         Cache(s"baseTableName_snaps", SnapshotTTL)
    
      lazy val getMetadataCache =
        Cache(s"baseTableName_metadata", MetadataTTL) 
    }
    

    As I like case classes I changed your Cache also to a case class:

    case class Cache(tableName: String, TTL: Int)
    

    As you can see I adjusted your Java code to correct Scala code.

    If you want to put it in the companion object, you could use implicits, like:

    object Cache {
    
      def getOpsCache(implicit baseTableName: String): Cache = 
         Cache(s"baseTableName_ops", OpsTTL)
    
      def getSnapshotCache(implicit baseTableName: String) =
         Cache(s"baseTableName_snaps", SnapshotTTL)
    
      def getMetadataCache(implicit baseTableName: String) =
        Cache(s"baseTableName_metadata", MetadataTTL) 
    }
    

    Then your client looks like:

    implicit val baseTableName: String = "baseName"
    
    cache.getSnapshotCache
    cache.getMetadataCache