我一直在关注这篇文章,它描述了如何通过Cake Pattern在Scala中实现依赖注入: http://jonasboner.com/real-world-scala-dependency-injection-di/
我对Scala有点新意,我承认其中一些已经过去了,到目前为止,我已经完成了以下工作:
// Setup the component and interface
trait AccountRepositoryComponent {
val accountRepository: AccountRepositoryInterface
trait AccountRepositoryInterface {
def message: String
}
}
// An implementation
trait MyAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Hello"
}
}
// Object to configure which implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService {
val repo = ComponentRegistry.accountRepository
def say: String = repo.message
}
println(AccountService.say)
我无法理解的是,我现在如何将假存储库传递给帐户服务,比如将输出更改为“测试”而不是“Hello”?
答案 0 :(得分:3)
可以通过多种方式对其进行修改以获得可行的结果,具体取决于您的情况可行的结果。我会在这里找到一个更简单的可能性。
首先,ComponentRegistry需要成为一个特征,因此它可以混合到AccountService中:
// Trait to configure which component implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService extends ComponentRegistry {
def say: String = accountRepository.message
}
println(AccountService.say)
这应该像以前一样打印“Hello”。要设置测试用例,请添加以下内容:
// Test implementation
trait TestAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Test"
}
}
// trait to configure test component implementations
trait TestComponentRegistry extends TestAccountRepositoryComponent {
val accountRepository = AccountRepository
}
现在我们可以设置一个使用测试组件的服务:
// Example service using the above
object AccountService extends TestComponentRegistry {
//val repo = ComponentRegistry.accountRepository
def say: String = accountRepository.message
}
println(AccountService.say)
这应该打印“测试”。
请注意,您可能希望您的AccountService根据其他mixins / traits定义其功能,这将期望相应的组件可用(分层到“蛋糕”),但不知道哪个实现在使用。例如:
trait CustomerApi {
self: AccountRepositoryComponent => // Expects an implementation of AccountRepositoryComponent to be mixed in
def say: String = accountRepository.message
}
现在实现方法say
时不知道它将与哪个版本的AccountRepository
进行交互,但必须提供一个(在编译时检查)。所以我们可以写:
object AccountService extends CustomerApi with ComponentRegistry
object TestAccountService extends CustomerApi with TestComponentRegistry
调用println(AccountService.say)
会生成"Hello"
,而调用println(TestAccountService.say)
会生成"Test"
。
答案 1 :(得分:0)
This post提供了一个简洁的例子(后面是一个有趣的替代方案)。