Jonas Bonr 的依赖注入策略似乎有限制——但也许我不明白它

发布于 2024-09-29 23:14:12 字数 847 浏览 3 评论 0原文

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

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

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

我在这里缺少什么?

I've read this article several times:

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

I think that I get it. However there's something that I'm not quite getting.

Looking at his UserService example, I see that he's set up UserRepositoryComponent to encapsulate UserRepository. But what I don't understand is why UserRepositoryComponent plays two roles: it encapsulates UserRepository and also offers a reference to a UserRepository object.

I'm trying to imagine how I would use this pattern if I wanted to create a service that depends on two UserRepository instances. Maybe the job of the new service is to copy users from a "source" UserRepository to a "destination" UserRepository. So I'm imagining something like this:

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

But this is different from the original pattern. In this case I'm defining the dependencies in the component itself instead of inheriting them from some other component. But this seems to me to be the right way to do it: the components should declare their dependencies, not instances of their included services.

What am I missing here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

城歌 2024-10-06 23:14:12

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

蛋糕模式不使用继承来声明依赖关系。您在 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 ...
}

In this case I'm defining the dependencies in the component itself instead of inheriting them from some other component.

The cake pattern doesn't use inheritance to declare dependencies. Did you see any "extend" in UserServiceComponent?

But this seems to me to be the right way to do it: the components should declare their dependencies, not instances of their included services.

But that's exactly what the cake pattern does: declare dependencies! Perhaps if the example contained def userRepositoryFactory = new UserRepository instead of val userRepository = new UserRepository, that would have been more clear?

So, let's go back to your example:

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

Let's see the things we can't do with that:

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

On the other hand...

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()
  ...
}

EDIT

Complementating the answer, let's consider two different needs:

  • I need many instances of UserRepository.

In this case, you are applying the pattern at the wrong level. In Jonas' example, UserRepository is at the level of a factory-providing singleton.

So, in that case, you wouldn't do UserRepository and UserRepositoryComponent but, say, UserRepositoryFactory and UserRepositoryFactoryComponent.

  • I need precisely two singleton UserRepository.

In this case, just do something like this:

trait UserRepositoryComponent {
  val sourceUserService: UserService
  val destinationUserService: UserService

  class UserService ...
}
各空 2024-10-06 23:14:12

我认为,乔纳斯在他的文章中提到了一种广泛接受的构建可扩展应用程序的方法称为复合软件构建,用几句话可以解释如下:整个应用程序(在元级别上编排)是由独立组件构建的程序集,而这些组件又是其他组件和服务的组合。就复合软件而言,'cake'(示例中的ComponentRegistry对象)是组件('UserServiceComponent'和'UserRepositoryComponent')等的集合。而在示例中组件包含服务实现,这在现实世界中几乎不可能发生。

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

trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent

  def copy = {...}
}

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

I assume, Jonas in his article refers to a widely accepted methodology of building scalable applications called Composite Software Construction that in a few words can be explained as follows: entire application (orchestrated on a meta-level) is an assembly built of independend components, which in their turn are compositions of other components and services. In terms of composite software, 'cake' (ComponentRegistry object in the example) is an assembly of components ('UserServiceComponent' and 'UserRepositoryComponent') etc. Whilst in the example components enclose service implementations it can hardly happen in the real-world.

In your example you don't need to define an inner class - you can put your workflow in an ordinary method:

trait CopyUserServiceComponent {
  val source: UserRepositoryComponent
  val destination: UserRepositoryComponent

  def copy = {...}
}

It perfectly conforms to original pattern - essential feature of the cake is not [only] specifying dependencies via self-type annotations, but also ability to abstract from the concrete implementation, till the moment when you need to build an assembly from the components.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文