scalainitializationpolymorphismclientcake-pattern

Abstracting the Database client in the cake pattern


I am trying to create an abstraction for a SearchService using the Cake pattern. This is what I have currently:

trait SearchServiceComponent{
  val searchService:SearchService

  trait SearchService{
      def searchForSomething(..):List[String]
      def updateIndex(..):Boolean
  } 
}

Lets say I have a DbSearchServiceComponent and LuceneSearchServiceComponent as follows:

trait DbSearchServiceComponent extends SearchServiceComponent{
   class DbSearchService extends SearchService{
           //Initialize the db client
           //Implement all the trait methods
   }
}

Similarly...

trait LuceneSearchServiceComponent extends SearchServiceComponent{
  class LuceneSearchService extends SearchService{
     //Initialize the lucene client
     //Implement all the trait methods
  }
}

The issue I have with the above snippet is that

I have initialized instances of lucene client and the db client in the Service implementations.

Ideally I would want to "mix-in" a "Client" base type that can be either a Db client or a Lucene client but I am pretty confused as to how to inject a polymorphic client type here.

Can somebody point out how I may be able to refactor the code so that I can inject different versions of the client to my implementations of the SearchService trait?


Solution

  • Not sure if I interpret your question correctly, but that's how you could use the cake pattern for this:

    trait SearchServiceComponent {
      val searchService: SearchService
    
      trait SearchService {
        def searchForSomething(...): List[String]
        def updateIndex(...): Boolean
      } 
    }
    
    trait DbSearchServiceComponent extends SearchServiceComponent {
       override val searchService = new SearchService {
        // Initialize client, implement methods
       }
    }
    
    trait trait LuceneSearchServiceComponent extends SearchServiceComponent {
       override val searchService = new SearchService {
        // Initialize client, implement methods
       }
    }
    

    and upon instantiation:

    val myLucenceApp = new Whatever with LuceneSearchServiceComponent
    val myDbApp = new Whatever with DbSearchServiceComponent
    

    where Whatever would typically be something along the lines of

    class Whatever { this: SearchServiceComponent =>
       // ... use `searchService` and do lots of other things
    }