【问题标题】:Difference between Dependency Injection (DI) and Inversion of Control (IOC)依赖注入 (DI) 和控制反转 (IOC) 之间的区别
【发布时间】:2010-09-13 10:47:13
【问题描述】:

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

我想开始使用其中一种或两种,但我对它们有何不同感到有些困惑。

【问题讨论】:

  • 控制反转通常指的是“容器”,而依赖注入指的是实际模式。但他们齐头并进。我建议阅读Martin Fowler's article 以了解该主题。
  • 依赖注入是你做的事情,它导致了一个称为控制反转的命令结构。它们具有内在联系。
  • DI是IoC的一种形式,我在this answer中对DI和IoC做了相当详细的解释
  • 我会说 DI 是 IOC 的一个特例。传统的控制去模块->从模块管理器请求模块,在DI中它被反转为模块管理器->从模块获取请求的依赖关系。
  • 所以换句话说,基本上 IoC 是使用 DI 的一种实现。我理解正确吗?

标签: dependency-injection inversion-of-control


【解决方案1】:

定义

控制反转是一种设计范式,其目标是减少对应用程序框架代码的具体实现的认识,并为应用程序的特定领域组件提供更多控制。在传统的自上而下设计的系统中,应用程序的逻辑流程和依赖意识从顶层组件(首先设计的组件)流向最后设计的组件。因此,控制反转几乎是对应用程序中控制和依赖意识的反转。

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

一起工作

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

示例

这些概念的一个例子是Reflector 中的插件框架。尽管应用程序在编译时对插件一无所知,但插件对系统有很大的控制权。在这些插件中的每一个上调用一个方法,Initialize if memory 服务,它将控制权交给插件。框架不知道他们会做什么,它只是让他们去做。控制已从主应用程序中获取并交给执行特定工作的组件;控制反转。

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

当时,工厂方法用于使用配置信息、反射和 Activator 对象(至少在 .NET 中)创建插件。今天,有一些工具,例如MEF,在注入依赖项时允许更广泛的选择,包括应用程序框架接受插件列表作为依赖项的能力。

总结

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

【讨论】:

  • 不,IoC 是一个较老的概念,它独立于 DI(不依赖于 IoC)。以 Struts 框架 (Java) 为例:它严重依赖 IoC,但没有使用 DI。
  • @Rogério - 你提出了一个很好的观点,这两个概念不需要彼此。我更新了我的答案以澄清这一点,然后快速描述一些框架如何将它们一起使用以允许更松散耦合的代码。
  • 最简单的 IoC 应用程序,可能是 ActionListener。事件处理代码不是按程序处理代码,而是委托给自定义代码。特此反转控件。
【解决方案2】:

了解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 容器通常只保留对其需要管理生命周期的对象的引用,或者为将来的注入重用的对象,例如单例或享元。当配置为每次调用容器创建某些组件的新实例时,容器通常只是忘记创建的对象。否则垃圾收集器将很难在不再使用时收集所有这些对象。

【讨论】:

  • 你真的看过“注射”的文章吗?国际奥委会确实不是这个答案所说的,根本不是。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 2015-01-09
      • 2015-07-30
      • 1970-01-01
      • 2011-04-24
      • 1970-01-01
      • 2011-05-27
      • 2012-02-05
      • 2011-02-08
      • 1970-01-01
      相关资源
      最近更新 更多