0

我第一次尝试使用蛋糕图案。

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

我想要的是用蛋糕模式构建一个全球应用程序。而且我想要该应用程序的另一个版本,除了存储库级别之外,它是相同的。

是否可以执行以下操作:

  trait application extends DefaultUserServiceComponent with MongoUserRepositoryComponent

  object realApplication extends application
  object fakeApplication extends FakeUserRepositoryComponent with application

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

4

1 回答 1

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的 's 是必要的,以便我们可以定义repository为一个函数,以便它可以用作FakeApplication. (使用super[type]覆盖仅适用于功能)。

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

于 2013-01-09T21:43:42.940 回答