根据Martin Fowler所写的论文,控制反转是程序控制流反转的原理:由外部源(框架、服务、其他组件)控制程序流,而不是由程序员控制程序流。就像我们把一个东西插入另一个东西。他提到了一个关于EJB 2.0的例子:

例如,会话Bean接口 定义ejbRemove, ejbPassivate (存储到二级存储),以及 ejbActivate(从被动恢复 状态)。你不能控制时间 这些方法被调用,只是什么 他们做的事。集装箱召唤我们,我们 别这么说。

这就导致了framework和library的区别:

控制反转是一个关键的部分 框架与框架的区别是什么 图书馆。图书馆本质上是一个 一组你可以调用的函数, 这些日子通常组织成 类。每次调用都要做一些工作 将控制权返回给客户端。

我认为,DI是IOC的观点,意味着对象的依赖关系是倒置的:而不是它控制自己的依赖关系、生命周期……其他东西可以帮你。但是,正如你告诉我的DI by hands, DI不一定是IOC。我们仍然可以有DI,没有IOC。

然而,在本文中(来自pococapsule, C/ c++的另一个IOC框架),它指出,由于IOC和DI, IOC容器和DI框架要比J2EE优越得多,因为J2EE将框架代码混合到组件中,因此它不是普通的旧Java/ c++对象(POJO/POCO)。

依赖注入模式以外的控制反转容器(存档链接)

附加阅读,了解旧的基于组件的开发框架的问题,这导致了上面的第二篇论文:为什么和什么反转控制(档案链接)

我的问题:IOC和DI到底是什么?我很困惑。基于pococapsule, IOC不仅仅是对象或程序员与框架之间控制的反转。


当前回答

控制反转是软件体系结构的一种通用设计原则,它有助于创建易于维护的可重用的模块化软件框架。

它是一种设计原则,其中控制流是从通用编写的库或可重用代码中“接收”的。

为了更好地理解它,让我们看看我们在早期是如何编写代码的。在过程式/传统语言中,业务逻辑通常控制应用程序的流程,并“调用”通用或可重用的代码/函数。例如,在一个简单的控制台应用程序中,我的控制流是由我的程序的指令控制的,这可能包括对一些一般可重用函数的调用。

print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);

//More print and scan statements
<Do Something Interesting>

//Call a Library function to find the age (common code)
print Age

与IoC相反,框架是“调用”业务逻辑的可重用代码。

例如,在基于windows的系统中,已经有一个框架可以创建按钮、菜单、窗口和对话框等UI元素。当我编写应用程序的业务逻辑时,将是框架的事件调用我的业务逻辑代码(当事件触发时),而不是相反。

尽管框架的代码不知道我的业务逻辑,但它仍然知道如何调用我的代码。这是通过使用事件/委托、回调等实现的。这里的流量控制是“反向的”。

因此,控制流不是依赖于静态绑定的对象,而是依赖于整个对象图和不同对象之间的关系。

依赖注入是一种实现IoC原则来解决对象依赖关系的设计模式。

简单地说,当您尝试编写代码时,您将创建和使用不同的类。一个类(类A)可以使用其他类(类B和/或D),因此,类B和类D是类A的依赖关系。

一个简单的类比是类Car。汽车可能依赖于其他类别,如引擎、轮胎等。

依赖注入建议不是依赖类(这里是类Car)创建它的依赖项(类Engine和类Tyre),而是应该用依赖项的具体实例注入类。

让我们用一个更实际的例子来理解。假设您正在编写自己的TextEditor。除此之外,您还可以使用拼写检查器,为用户提供检查文本中的错别字的工具。这样一个代码的简单实现可以是:

Class TextEditor
{

    //Lot of rocket science to create the Editor goes here

    EnglishSpellChecker objSpellCheck;
    String text;

    public void TextEditor()

    {   

        objSpellCheck = new EnglishSpellChecker();

    }

    public ArrayList <typos> CheckSpellings()
    {

        //return Typos;

    }

}

乍一看,一切都很美好。用户将编写一些文本。开发人员将捕获文本并调用CheckSpellings函数,并找到他将显示给用户的拼写错误列表。

一切似乎都很好,直到有一天,一个用户开始在编辑器中编写法语。

为了提供对更多语言的支持,我们需要更多的拼写检查器。可能是法语、德语、西班牙语等。

在这里,我们创建了一个紧密耦合的代码,其中“English”SpellChecker与我们的TextEditor类紧密耦合,这意味着我们的TextEditor类依赖于EnglishSpellChecker,换句话说,English spellcheker是TextEditor的依赖项。我们需要消除这种依赖关系。此外,我们的文本编辑器需要一种方法来保存任何拼写检查器的具体引用,基于开发人员在运行时的自由裁量权。

因此,正如我们在DI的介绍中看到的,它建议类应该注入它的依赖项。因此,将所有依赖项注入到被调用的类/代码应该是调用代码的责任。所以我们可以把代码重构为

interface ISpellChecker
{

    Arraylist<typos> CheckSpelling(string Text);

}

Class EnglishSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}



Class FrenchSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}

在我们的例子中,TextEditor类应该接收ISpellChecker类型的具体实例。

现在,可以在构造函数、公共属性或方法中注入依赖项。

让我们尝试使用构造函数DI来改变我们的类。修改后的TextEditor类看起来像这样:

Class TextEditor

{

    ISpellChecker objSpellChecker;

    string Text;



    public void TextEditor(ISpellChecker objSC)

    {

        objSpellChecker = objSC;

    }



    public ArrayList <typos> CheckSpellings()

    {

        return objSpellChecker.CheckSpelling();

    }

}

因此,在创建文本编辑器时,调用代码可以将适当的拼写检查器类型注入到TextEditor的实例中。

你可以在这里阅读完整的文章

其他回答

IoC -控制反转是一个通用术语,与语言无关,它实际上不是创建对象,而是描述如何创建时尚对象。

依赖注入是一个具体的术语,我们通过使用不同的注入技术,即Setter注入、构造函数注入或接口注入,在运行时提供对象的依赖关系。

IoC(控制反转):这是一个通用术语,以多种方式实现(事件,委托等)。

依赖注入:依赖注入是IoC的一个子类型,通过构造函数注入、setter注入或接口注入实现。

但是,Spring只支持以下两种类型:

Setter Injection Setter-based DI is realized by calling setter methods on the user’s beans after invoking a no-argument constructor or no-argument static factory method to instantiate their bean. Constructor Injection Constructor-based DI is realized by invoking a constructor with a number of arguments, each representing a collaborator.Using this we can validate that the injected beans are not null and fail fast(fail on compile time and not on run-time), so while starting application itself we get NullPointerException: bean does not exist. Constructor injection is Best practice to inject dependencies.

10c - DIP - DI

控制反转(IOC) 依赖倒置原理(DIP) 依赖注入(DI)

IOC:描述某些软件架构设计的一个方面的抽象原理,与过程式编程相比,系统的控制流是反向的。

2-DIP:是面向对象编程(Object - Oriented Programming, OOP)原理(SOLID中的D)。

3-DI:是一种实现控制反转的软件设计模式,允许程序设计遵循依赖反转原则。

IOC和DIP是两个不相交的集合,DIP是DI、服务定位器和其他一些模式的超集合

简而言之,IoC是一个更广泛的术语,包括但不限于DI

术语控制反转(IoC)最初指的是任何一种编程风格 框架或运行时控制程序流

在DI有名字之前,人们开始把管理依赖的框架称为反转 很快,IoC的含义逐渐转向了特定的含义:对依赖项的控制反转。

控制反转(IoC)意味着对象不创建它们所依赖的其他对象来完成工作。相反,他们从外部来源(例如,xml配置文件)获取所需的对象。

依赖注入(DI)意味着这是在没有对象干预的情况下完成的,通常由传递构造函数参数和设置属性的框架组件完成。

我在Dzone.com上找到了最好的例子,这对理解IOC和DI之间的真正区别非常有帮助

“IoC就是让别人为你创建对象。”因此,与其在代码中写入“new”关键字(例如,MyCode c=new MyCode()),对象是由其他人创建的。这个“其他人”通常被称为IoC容器。这意味着我们将责任(控制)移交给容器以获得对象的实例,这称为控制反转。 意思是你不用new操作符来创建对象,而是让容器来为你做。

   DI(Dependency Injection):  Way of injecting properties to an object is 
   called 
  Dependency injection.
   We have three types of Dependency injection
    1)  Constructor Injection
    2)  Setter/Getter Injection
    3)  Interface Injection
   Spring will support only Constructor Injection and Setter/Getter Injection.

阅读全文IOC和全文DI