简短回答:不。您将继承相互冲突的成员。见以下代码sn -p:
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] 覆盖仅适用于函数)。
编辑:最后,蛋糕模式的目的是开发一个不需要像我提供的最后一个代码 sn-p 那样覆盖的层次结构。实际上,特征Application 根本不应该存在,只有RealApplication 和FakeApplication。 (在第二个代码 sn-p 中,我基本上只是将 UserServiceComponent 重命名为 Application)。