Dependency injection 依赖注入究竟是如何减少耦合的?

Dependency injection 依赖注入究竟是如何减少耦合的?,dependency-injection,Dependency Injection,我已经读了很多关于依赖注入的书,但我不知道,它实际上是如何减少耦合的 我对DI的类比是,所有组件都注册在一个容器中,所以它们就像是在一个宝箱中。要获得一个组件,显然首先要注册它,但随后必须查询宝箱(这就像一层间接寻址)。这是正确的类比吗?不过,这并没有说明“注射”是如何发生的(这与这个类比有什么关系?) 多亏了如果正确使用接口,耦合尤其会减少 如果客户机只知道接口,那么现在可能性就大了。您可以自由地注入自己的实现或代理版本;您可以在客户不知情的情况下,向其提供各方面的建议;您可以在测试期间轻松地

我已经读了很多关于依赖注入的书,但我不知道,它实际上是如何减少耦合的

我对DI的类比是,所有组件都注册在一个容器中,所以它们就像是在一个宝箱中。要获得一个组件,显然首先要注册它,但随后必须查询宝箱(这就像一层间接寻址)。这是正确的类比吗?不过,这并没有说明“注射”是如何发生的(这与这个类比有什么关系?)


多亏了

如果正确使用接口,耦合尤其会减少


如果客户机只知道接口,那么现在可能性就大了。您可以自由地注入自己的实现或代理版本;您可以在客户不知情的情况下,向其提供各方面的建议;您可以在测试期间轻松地模拟它。客户不需要知道具体的类型,如果您只是简单地称之为“新的”。

与您的组件在宝箱中的类比: 一个没有依赖注入的系统(比如说宝藏抛光机)必须能够从宝箱本身挑选物品。它必须了解依赖关系的性质,以便根据当前上下文选择正确的宝藏进行润色。因此,耦合

在DI场景中,你的宝藏抛光师根本不需要知道宝箱的存在。它需要知道的是,在某个时刻(最好是在创建时),抛光机将被提供(注入)一个实现
ITreasure

interface ITreasure
{
    void PolishMe();
}

因此,您的实现类与您的宝箱解耦。

在DI中,一个组件仅通过定义良好的接口调用另一个组件,所有组件通过配置而不是代码“粘合”在一起。
因此,我们可以仅通过重新配置来交换应用程序使用的实现。
例如,在容器中,您可以将依赖项注入可视化为反向查找(如果您使用了JNDI)。 您可以声明类(充当bean)所需的内容,而不是硬编码资源/模块名称。容器负责在运行时提供所有内容。
这个术语是由Martin Fowler创造的,您可以查看他关于依赖项注入(DI)本身不会减少耦合的概念的文章,因为依赖依赖项的组件仍然与其依赖项耦合。然而,DI所完成的是从组件本身中删除查找依赖项的责任,并将该责任放在其他地方

依赖DI的组件在依赖关系方面是完全被动的。组件中没有写着“创建此依赖项的新实例”或“走出去获取此依赖项”的代码。依赖关系被赋予(注入)组件,通常是在组件本身由其他对象创建时

这种创建(或请求创建)依赖关系的责任倒置称为控制反转(IoC)

那么,如果组件不知道如何创建或请求依赖关系,那么责任在哪里?通常在专门为依赖项解析创建的对象中,通常称为IoC容器。在你的比喻中,这是你的“宝箱”。IoC容器包含的说明基本上是这样的:“当有人要求时,给他们其中一个。IoC容器通常可以检查它被要求创建的组件,找出它的依赖项,并创建它们,沿着“依赖项链”走,直到所有依赖项都被解决

当决定由谁来向容器请求组件的依赖关系时,思想上的重大转变,即注入?如果没有DI,组件本身将向容器请求其依赖关系。然而,使用DI时,要求容器“解析”组件依赖关系的责任落在创建或使用组件的任何人身上。创建组件时,无论创建组件的是什么,都有责任提供所有依赖项。组件不知道或不关心它们是如何创建的,只知道它们是如何创建的

现在,如果依赖项被定义为一个具体的实现,那么组件仍然与该具体的实现紧密耦合,即使它正在被注入。DI本身并没有从这个意义上减少耦合。但是,如果依赖项被定义为接口,那么组件就不关心或不知道具体实现是什么,也不知道它是如何创建的。它仍然与依赖项耦合,但它是一个非常松散的耦合


从这个意义上说,“依赖注入”和“接口编程”结合在一起可以创建非常松散耦合、高度灵活的组件。

所以DI只是(抽象)工厂的另一个词?听起来也非常类似于ASP.NET“提供者”模型。它真的与这些不同吗?抽象工厂是一个很好的同义词。我不知道提供商的型号。@StingyJack,dufftmo:不知道。在抽象工厂中,您使用工厂对象来获得具体的实现。使用DI,在运行时提供或“注入”具体实现。客户端代码不会创建工厂来获取对象。此责任已被委派,我对DI的理解不需要更正。“在抽象工厂中,您使用工厂对象来获得具体的实现”——这正是依赖项注入所做的。工厂已经创建,客户机必须在启动时有一个对它的引用才能得到对象实现。您没有在对话中添加此评论。您不必使用IoC容器框架来实现DI。具有接口类型构造函数参数的类可以说是使用构造函数注入,即使调用代码只是传递一个新实例