8

我知道依赖注入原理都是关于解耦代码的。不是在类中创建实例,而是注入它们,这使它们松散耦合。

现在,如果我必须传递一组将在整个应用程序中通过多个类使用的对象,我可以创建一个容器(通常称为依赖注入容器)。

这正是我正在做的,因为我必须传递一个配置对象、一个记录器对象、一个翻译器对象等,它们将在我的应用程序的几个类实例中使用。我将整个容器传递给几个类,即使并非所有类都需要访问容器中的所有对象。这使我想到了以下问题:如果我创建一个全局注册表并将对象放入其中,然后像 Registry::getInstance()->get('logger'); 一样检索它们,有什么区别?? 无论我使用全局注册表还是依赖容器,类实例都可以访问容器或注册表中的所有对象,即使他们不需要查看/访问所有对象。

结论:如果我沿着我的类或全局注册表传递依赖注入容器有什么区别?

4

3 回答 3

6

注意:有时人们使用不同名称的注册表。我见过的常见的有:定位器、上下文和系统。

使用全局注册表会导致您的代码与所述注册表的类名相关联。这意味着您无法独立测试您的代码。而注册表的设置方式取决于您:您永远无法知道需要哪个实例。

人们将 DI 容器与注册表混淆是很常见的。

DI Container 不是您注入到类中的东西。相反,它是对工厂的增强:它确定类需要在构造函数中注入Foo实例。Bar然后,根据设置,它要么获取新实例,Bar要么使用现有实例,以提供所述依赖关系。

  • 在一个简单的工厂中,您通常必须对将被注入的依赖项进行硬编码。在这种情况下,工厂可以构建什么,受到类构造函数的“足迹”的限制。

  • 当 factory 用作 DI 容器时,它可以生成具有各种依赖关系的实例。在此设置中,您的工厂专注于构建与某些特定名称空间(或其他高级)逻辑类组相关联的实例。

于 2013-06-17T07:56:54.790 回答
5

我认为这里缺少的一点是CompositionRoot。根据 DI 原则,一旦您在 Composition Root 中定义了绑定,您就可以在整个应用程序中使用该引用。这就是 DI Container 带来的价值。

根据定义,“组合根是应用程序中(最好)唯一的位置,模块组合在一起。”

我将补充一点,Composition Root 也是一个独特的位置,所有关于您的应用程序行为的重要决策都在这里发生。那就是在什么情况下使用什么对象。这是 OO 系统的核心,其中对象之间的交互传递了系统的行为。

于 2013-06-17T11:16:07.573 回答
0

我同意 teresko 所说的大部分内容,我想补充几点:

  • 如果您觉得您的服务在许多不同的实例之间共享,那么您可以将它们注册为容器中的 Singelton,但如果这对您来说是个问题,您将不得不考虑多线程。
  • 每当您在依赖注入场景中感到背靠墙时,请记住工厂(抽象工厂模式)几乎总是解决方案。
  • 您提到的服务似乎是一个横切关注点,因此我将使用 AOP 技术来避免因这些关注点而使我的代码库膨胀,这将使代码更加清晰。
于 2013-06-17T09:38:21.430 回答