仅替换全局蛋糕模式应用程序上的存储库

时间:2013-01-09 21:23:33

标签: scala mixins cake-pattern

我第一次尝试使用蛋糕模式。

我有点理解它是如何工作的,但是想知道是否有可能混合已经混合的特性或类似的东西。

我想要的是用蛋糕模式构建一个全局应用程序。 我希望该应用程序的另一个版本是相同的,除了在存储库级别。

是否可以执行以下操作:

  trait application extends DefaultUserServiceComponent with MongoUserRepositoryComponent

  object realApplication extends application
  object fakeApplication extends FakeUserRepositoryComponent with application

我的意思是:在使用假存储库构建虚假应用程序时重用已经构建的应用程序?

1 个答案:

答案 0 :(得分:2)

简短回答:不。你会继承冲突的成员。请参阅以下代码段:

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

相反,为了获得所需的行为,请将Application定义为:

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

要保持OP中给出的层次结构,您需要修改代码:

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
}

其他private val _repository是必需的,以便我们可以将repository定义为函数,以便它可以在FakeApplication中用作覆盖。 (使用super[type]覆盖仅适用于函数)。

编辑:最后,蛋糕模式的目的是开发一个层次结构,其中一个不需要覆盖,就像我提供的最后一个代码片段一样。实际上,特征Application根本不应存在,只有RealApplicationFakeApplication。 (在第二段代码中,我基本上只是将UserServiceComponent重命名为Application)。