依赖注入(DI)和控制反转(IOC)之间的区别


117

我已经看到了很多有关依赖注入(DI)和控制反转(IOC)的参考,但是我真的不知道它们之间是否有区别。

我想开始使用它们中的一个或两个,但是对于它们之间的区别我有些困惑。


控制反转通常是指“容器”,而依赖注入是指实际模式。但是他们并驾齐驱。我建议阅读Martin Fowler的文章以了解该主题。
本霍夫斯坦

依赖注入是您要做的事情,它会导致一个称为控制反转的命令结构。它们具有内在的联系。

2
DI是IoC的一种形式,我在此答案中

2
我想说DI是IOC的特例。传统控制从模块管理器转到模块->请求模块,在DI中将其转换为模块管理器->从模块获取请求的依赖项。
拉法尔Dowgird

因此,换句话说,IoC基本上是使用DI的实现。我能正确理解吗?
dance2die

Answers:


53

定义

控制反转是一种设计范例,其目的是减少对应用程序框架代码对具体实现的了解,并为应用程序的特定领域组件提供更多控制。在传统的自上而下设计的系统中,应用程序和依赖关系意识的逻辑流程从最先设计的组件到最后设计的组件。因此,控制反转几乎是应用程序中控制和依赖关系感知的字面反转。

依赖注入是一种模式,用于创建其他类依赖的类的实例,而在编译时不知道将使用哪种实现来提供该功能。

合作

控制反转可以利用依赖注入,因为需要一种机制才能创建提供特定功能的组件。存在并使用了其他选项,例如激活器,工厂方法等,但是当框架类可以接受所需的依赖项时,框架不需要引用那些实用程序类。

例子

这些概念在起作用的一个示例是Reflector中的插件框架。即使应用程序在编译时对插件一无所知,插件也具有对系统的大量控制权。在这些插件中的每一个上调用一个方法,如果有内存可用,则初始化,将控制权传递给插件。该框架不知道他们将要做什么,只是让他们去做。控制已从主应用程序中获取,并交给了执行特定工作的组件;控制反转。

该应用程序框架允许通过各种服务提供商访问其功能。插件在创建时会获得对服务提供商的引用。这些依赖关系允许插件添加自己的菜单项,更改文件的显示方式,在适当的面板中显示其自身的信息等。由于依赖关系是通过接口传递的,因此实现可以更改,并且更改不会中断只要合同保持原样就可以。

当时,使用工厂方法通过配置信息,反射和Activator对象(至少在.NET中)来创建插件。如今,有一些工具(MEF用于其中之一)在注入依赖项时提供了更多选择,包括应用程序框架可以接受一系列插件作为依赖项。

摘要

虽然可以使用这些概念并独立提供好处,但它们在一起可以编写更加灵活,可重用和可测试的代码。因此,它们是设计面向对象解决方案中的重要概念。


3
不,IoC是一个较旧的概念,它独立于DI(不依赖于IoC)。例如,采用Struts框架(Java):它高度依赖IoC,但不使用DI。
罗杰里奥

1
@Rogério-您很好地指出了这两个概念并不需要。我更新了答案以澄清这一点,然后快速描述一些框架如何将它们一起使用,以允许代码之间的耦合更为宽松。
Chuck

IoC的最简单的应用程序可能是ActionListener。而不是按程序处理代码,而是将事件处理代码委托给自定义代码。从而反转控制。
mike

0

了解IOC和DI的好文章 http://martinfowler.com/articles/injection.html

IOC(控制反转)

国际奥委会的手段

  1. 编码到接口(一个组件应依赖于另一个组件的接口而不是impl),例如

    interface iComp_2 {...}
    
    class Comp_1 {
        iComp_2 c2 = ….;
    }
    
  2. 删除组件实现特定的代码,例如

    Comp_1 {
        iComp_2 c2 = getComp_2_Impl(); // not new Comp_2_Impl();
    }
    

可以通过以下任一方式来实现IOC:

1. DI(依赖注入)

3 types of DI

1.1 Constructor Injection

1.2 Setter Injection

1.3 Interface Injection

2.服务定位器

DI(依赖注入)容器

运行时impl确定而不是编译时:在运行时根据一些配置文件确定要使用的接口的具体实现(因此在编译时,我们不知道将使用哪个impl,从而提高了应用程序的可配置性) 。它是在“运行时”确定不同模块之间的具体关系的实现。

依赖项注入后实例化impl:确定impl后,它首先创建所有依赖项(在配置文件中指定),然后将这些依赖项注入该impl中,从而实例化该impl

实例生命周期管理:DI容器通常仅保留其管理生命周期所需的对象的引用,或者将其重复用于将来的注入,例如单例或重量级。当配置为每个对容器的调用创建某些组件的新实例时,容器通常只会忘记创建的对象。否则,垃圾收集器在不再使用时将很难收集所有这些对象。


6
您真的读过“注射”文章吗?国际奥委会并不完全代表这个答案。
罗杰里奥

-3

我会说“控制反转”是一种设计系统的方式,其中所有模块都被视为抽象实体。

并且,“依赖注入”是在“运行时”确定不同模块之间的具体关系的实现。


-4

控制反转是一个通用概念,在功能语言中,通常使用延续来完成。让我们编写一个API,其中双方都是“调用方”,而没有一个都是“被调用方”。在其他更静态的环境中,您没有这种便利,因此您需要使用此技巧将提示插入控制流。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.