0

I'm trying to use the cake pattern for the first time.

I kind of understand how it works, but would like to know if it is possible to mix already mixed traits or something like that.

What I would like is to build a global application with the cake pattern. And I want another version of that application which would be the same, except at the repository level.

Is it possible to do something like:

  trait application extends DefaultUserServiceComponent with MongoUserRepositoryComponent

  object realApplication extends application
  object fakeApplication extends FakeUserRepositoryComponent with application

I mean: reusing the already built application, when building a fake application using fake repositories?

Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419

1 Answers1

2

Short answer: No. You would be inheriting conflicting members. See the following code snippet:

trait Repository {def authenticate(username: String, password: String): String}

trait UserServiceComponent {self: UserRepositoryComponent =>
  val userService: UserService = new UserService
  class UserService {
    def authenticate(username: String, password: String): String =
      repository.authenticate(username, password)
  }
}

trait UserRepositoryComponent {
  def repository: Repository
}

trait MongoUserRepositoryComponent extends UserRepositoryComponent {
  val repository: Repository =
    new Repository {def authenticate(username: String, password: String) = "MongoAuthed"}
}

trait MockUserRepositoryComponent extends UserRepositoryComponent {
  val repository: Repository =
    new Repository {def authenticate(username: String, password: String) = "MockAuthed"}
}

trait Application extends UserServiceComponent with MongoUserRepositoryComponent

object RealApplication extends Application
// The following will be an error: "object FakeApplication inherits conflicting members:"
object FakeApplication extends Application with MockUserRepositoryComponent

Instead, to have the desired behavior, define Application as such:

trait Application extends UserServiceComponent {self: UserRepositoryComponent =>}
object RealApplication extends Application with MongoUserRepositoryComponent
object FakeApplication extends Application with MockUserRepositoryComponent

To keep the hierarchy given in the OP, you would need to modify the code as such:

trait MongoUserRepositoryComponent extends UserRepositoryComponent {
  private val _repository = new Repository {def authenticate(username: String, password: String) = "MongoAuthed"}
  def repository: Repository = _repository
}

trait MockUserRepositoryComponent extends UserRepositoryComponent {
  private val _repository = new Repository {def authenticate(username: String, password: String) = "MockAuthed"}
  def repository: Repository = _repository
}

trait Application extends UserServiceComponent with MongoUserRepositoryComponent

object RealApplication extends Application
object FakeApplication extends Application with MockUserRepositoryComponent {
  override val repository: Repository = super[MockUserRepositoryComponent].repository
}

The additional private val _repository's are necessary so that we can define repository as a function, so that it can be used as an override in FakeApplication. (Using super[type] to override only works with functions).

EDIT: In the end, the purpose of the cake pattern is to develop a hierarchy where one does not need to override as in the last code snippet I provided. In reality, the trait Application should not exist at all, only RealApplication and FakeApplication. (In the 2nd code snippet I'm essentially doing nothing more than renaming UserServiceComponent to Application).

Alex DiCarlo
  • 4,851
  • 18
  • 34
  • 1
    Edited to make it more "cakey" and to be more similar to http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di/ which is a great reference for the cake pattern (and incidentally, is the example given in your question) – Alex DiCarlo Jan 10 '13 at 00:50
  • Can you check this question please? :) http://stackoverflow.com/questions/14532368/cake-pattern-one-component-per-implementation-or-one-component-per-trait – Sebastien Lorber Jan 26 '13 at 11:28