1

我一直在关注这篇文章,它描述了如何通过 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)

我不明白的是我现在如何将假存储库传递给帐户服务,比如将输出更改为“测试”而不是“你好”?

4

2 回答 2

3

可以通过多种方式对其进行修改以实现可行的结果,具体取决于对您的情况而言什么是可行的结果。我将在这里介绍一个更简单的可能性。

首先,ComponentRegistry 需要成为一个 trait,所以它可以混入 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 根据其他混合/特征来定义其功能,这会期望适当的组件可用(分层到“蛋糕”中),但不知道正在使用哪个实现。例如:

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"

于 2013-11-12T23:32:09.217 回答
0

这篇文章提供了一个简洁的例子(后面是一个有趣的替代方案)。

于 2013-11-12T23:38:25.060 回答