JonasBonér的依赖注入策略似乎有限 - 但也许我不明白

Wil*_*urn 6 dependency-injection scala

我已多次阅读这篇文章:

http://jonasboner.com/2008/10/06/real-world-scala-dependency-injection-di.html

我想我明白了.然而,有一些我不太了解的东西.

看看他的UserService示例,我看到他设置了UserRepositoryComponent来封装UserRepository.但我不明白的是UserRepositoryComponent扮演两个角色的原因:它封装了UserRepository,还提供了对UserRepository对象的引用.

我试图想象如果我想创建依赖于两个 UserRepository实例的服务,我将如何使用此模式.也许新服务的工作是将用户从"源"UserRepository复制到"目标"UserRepository.所以我想象的是这样的:

trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent
  class CopyUserServiceComponent { 
    ... 
  }
}
Run Code Online (Sandbox Code Playgroud)

但这与原始模式不同.在这种情况下,我在组件本身中定义依赖项,而不是从其他组件继承它们.但在我看来,这是正确的方法:组件应该声明它们的依赖关系,而不是它们包含的服务的实例.

我在这里错过了什么?

Dan*_*ral 4

在本例中,我在组件本身中定义依赖项,而不是从其他组件继承它们。

蛋糕模式不使用继承来声明依赖关系。你看到任何“扩展”了吗UserServiceComponent

但在我看来,这是正确的方法:组件应该声明它们的依赖项,而不是它们包含的服务的实例。

但这正是蛋糕模式的作用:声明依赖关系!也许如果这个例子包含def userRepositoryFactory = new UserRepository而不是val userRepository = new UserRepository,那就更清楚了?

那么,让我们回到你的例子:

trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent
  class CopyUserServiceComponent { 
    ... 
  }
}
Run Code Online (Sandbox Code Playgroud)

让我们看看我们不能用它做的事情:

trait CopyUserServiceComponent {
  // The module will need to see my internals!
  private val source: UserRepositoryComponent
  private val destination: UserRepositoryComponent
  class CopyUserServiceComponent { 
    ... 
  }
}

trait CopyBigUserServiceComponent extends CopyServiceComponent {
  // Any change in implementation will have to be reflected in the module!
  val tmp: UserRepositoryComponent
  ...
}
Run Code Online (Sandbox Code Playgroud)

另一方面...

trait UserRepositoryComponent {
  val userRepositoryFactory: () => UserRepository

  class UserRepository {
    ...
  }
} 

trait CopyUserServiceComponent {
  self: UserRepositoryComponent =>
  // No problem here
  private val source: UserRepository = userRepositoryFactory()
  private val destination: UserRepository = userRepositoryFactory()
  class CopyUserServiceComponent { 
    ... 
  }
}

trait CopyBigUserServiceComponent extends CopyServiceComponent {
  self: UserRepositoryComponent =>
  // No problem here either
  val tmp: : UserRepository = userRepositoryFactory()
  ...
}
Run Code Online (Sandbox Code Playgroud)

编辑

为了补充答案,让我们考虑两种不同的需求:

  • 我需要很多UserRepository.

在这种情况下,您在错误的级别应用了该模式。在 Jonas 的示例中,UserRepository处于工厂提供单例的级别。

所以,在这种情况下,你不会做UserRepositoryandUserRepositoryComponent但是,说,UserRepositoryFactoryand UserRepositoryFactoryComponent

  • 我正好需要两个单例UserRepository

在这种情况下,只需执行以下操作:

trait UserRepositoryComponent {
  val sourceUserService: UserService
  val destinationUserService: UserService

  class UserService ...
}
Run Code Online (Sandbox Code Playgroud)