首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Jonas Bonér的依赖注入策略似乎是有限的--但也许我不明白

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

Stack Overflow用户
提问于 2010-11-02 15:06:25
回答 2查看 632关注 0票数 6

我读过这篇文章好几遍:

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

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

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

如果我想要创建一个依赖于两个UserRepository实例的服务,我将如何使用这种模式。也许新服务的工作是将用户从“源”UserRepository复制到“目标”UserRepository。所以我在想象这样的事情:

代码语言:javascript
运行
复制
trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent
  class CopyUserServiceComponent { 
    ... 
  }
}

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

我在这里错过了什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-11-02 21:18:09

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

蛋糕模式不使用继承来声明依赖项。你在UserServiceComponent中看到“扩展”了吗?

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

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

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

代码语言:javascript
运行
复制
trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent
  class CopyUserServiceComponent { 
    ... 
  }
}

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

代码语言:javascript
运行
复制
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
  ...
}

另一方面..。

代码语言:javascript
运行
复制
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

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

代码语言:javascript
运行
复制
trait UserRepositoryComponent {
  val sourceUserService: UserService
  val destinationUserService: UserService

  class UserService ...
}
票数 4
EN

Stack Overflow用户

发布于 2010-11-02 20:15:21

我猜想,Jonas在他的文章中提到了一个被广泛接受的名为构建可伸缩应用程序的方法复合软件建设,用几个词可以这样解释:整个应用程序(在元级上编排)是一个由独立组件构建的程序集,而这些组件又是其他组件和服务的组合。在复合软件方面,'cake' (示例中的ComponentRegistry对象)是组件('UserServiceComponent‘和'UserRepositoryComponent')等组件的集合,而在示例中,组件包含服务实现,这在现实世界中几乎不可能发生。

在您的示例中,您不需要定义内部类--您可以将工作流放在一个普通的方法中:

代码语言:javascript
运行
复制
trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent

  def copy = {...}
}

它完全符合原始模式--蛋糕的基本特性不仅是通过自类型注释指定依赖项,而且还可以从具体的实现中抽象出来,直到您需要从组件构建程序集的时刻。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4078991

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档