我已经读过这篇文章几次:

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 {
    ...
  }
}

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

我在这里想念什么?

最佳答案



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



但这正是蛋糕模式所做的:声明依赖项!也许如果示例包含def userRepositoryFactory = new UserRepository而不是val userRepository = new UserRepository,那会更清楚吗?

因此,让我们回到您的示例:

trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent
  class CopyUserServiceComponent {
    ...
  }
}

让我们看看我们无法做到的事情:
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
  ...
}

另一方面...
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()
  ...
}

编辑

为了补充答案,让我们考虑两个不同的需求:
  • 我需要UserRepository的许多实例。

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

    因此,在那种情况下,您将不会执行UserRepositoryUserRepositoryComponent,而是说UserRepositoryFactoryUserRepositoryFactoryComponent
  • 我恰好需要两个单例UserRepository

  • 在这种情况下,只需执行以下操作:
    trait UserRepositoryComponent {
      val sourceUserService: UserService
      val destinationUserService: UserService
    
      class UserService ...
    }
    

    关于scala - 乔纳斯·博内尔(JonasBonér)的依赖注入(inject)策略似乎很局限-但也许我不明白,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/4078991/

    10-10 23:47