代码之家  ›  专栏  ›  技术社区  ›  Willis Blackburn

Jonas Bonér的依赖注入策略似乎有局限性——但也许我不明白

  •  6
  • Willis Blackburn  · 技术社区  · 14 年前

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

    我想我明白了。不过,有些事我不太明白。

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

    我试图想象如果我想创建一个依赖于 用户存储库实例。也许新服务的工作是将用户从“源”用户存储库复制到“目标”用户存储库。所以我在想象这样的事情:

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

    但这与最初的模式不同。在本例中,我是在组件本身中定义依赖项,而不是从其他组件继承依赖项。但在我看来,这是正确的方法:组件应该声明它们的依赖项,而不是它们所包含服务的实例。

    我错过了什么?

    2 回复  |  直到 14 年前
        1
  •  4
  •   Daniel C. Sobral    14 年前

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

    cake模式不使用继承来声明依赖项。你有没有看到 UserServiceComponent ?

    但cake模式就是这么做的:声明依赖关系!如果这个例子包含 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

    用户存储库 是一家提供单件商品的工厂。

    用户存储库 UserRepositoryComponent 但是,比方说, UserRepositoryFactory UserRepositoryFactoryComponent .

    • 用户存储库 .

    在这种情况下,只需这样做:

    trait UserRepositoryComponent {
      val sourceUserService: UserService
      val destinationUserService: UserService
    
      class UserService ...
    }
    
        2
  •  1
  •   Vasil Remeniuk    14 年前

    methodology of building scalable applications 打电话 Composite Software Construction 简而言之,可以这样解释:整个应用程序(在元级别上编排)是由独立组件构建的程序集,而独立组件又是其他组件和服务的组合。在复合软件方面, '蛋糕' ( ComponentRegistry 示例中的对象)是组件的集合(“UserServiceComponent”和“UserRepositoryComponent”)等。而在示例中,组件包含服务实现,在现实世界中几乎不可能发生这种情况。

    trait CopyUserServiceComponent {
      val source: UserRepositoryComponent
      val destination: UserRepositoryComponent
    
      def copy = {...}
    }
    

    它完全符合最初的模式——蛋糕的基本特性不仅是通过自类型注释指定依赖关系,而且还能够从具体实现中抽象出来,直到需要从组件中构建程序集为止。

    推荐文章