根据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不仅仅是对象或程序员与框架之间控制的反转。


当前回答

控制反转(IoC)模式是关于提供任何类型的回调,它“实现”和/或控制反应,而不是我们自己直接操作(换句话说,反转和/或重定向控制到外部处理程序/控制器)。

例如,不是让应用程序调用库(也称为工具包)提供的实现,而是库和/或框架调用应用程序提供的实现。

依赖注入(DI)模式是IoC模式的一个更具体的版本,其中实现通过构造函数/设置器/服务查找传递到对象中,对象将“依赖”这些以正确地行为。

每个DI实现都可以被认为是IoC,但不应该称之为IoC,因为实现依赖注入比实现回调更难(不要使用通用术语“IoC”来降低产品的价值)。

例如,不使用DI的IoC将是Template模式,因为实现只能通过子类化来更改。

依赖注入框架被设计为使用依赖注入,并且可以定义接口(或Java中的注释)以方便在实现中传递。

IoC容器是可以在编程语言之外工作的依赖注入框架。在某些情况下,您可以在元数据文件(例如XML)中配置要使用的实现,这是侵入性较小的。有一些可以做IoC,这通常是不可能的,比如在切入点注入实现。

参见Martin Fowler的文章。

其他回答

IOC表示外部类管理应用程序的类,而外部类表示容器管理应用程序类之间的依赖关系。 IOC的基本概念是程序员不需要创建对象,而是描述如何创建对象。

IoC容器执行的主要任务是: 实例化应用程序类。配置对象。组装对象之间的依赖关系。

DI是通过使用setter注入或构造函数注入在运行时提供对象依赖关系的过程。

让我们从SOLID的D开始,看看Scott Millett的书《Professional ASP. IoC》中的DI和IoC。NET设计模式":

Dependency Inversion Principle (DIP) The DIP is all about isolating your classes from concrete implementations and having them depend on abstract classes or interfaces. It promotes the mantra of coding to an interface rather than an implementation, which increases flexibility within a system by ensuring you are not tightly coupled to one implementation. Dependency Injection (DI) and Inversion of Control (IoC) Closely linked to the DIP are the DI principle and the IoC principle. DI is the act of supplying a low level or dependent class via a constructor, method, or property. Used in conjunction with DI, these dependent classes can be inverted to interfaces or abstract classes that will lead to loosely coupled systems that are highly testable and easy to change. In IoC, a system’s flow of control is inverted compared to procedural programming. An example of this is an IoC container, whose purpose is to inject services into client code without having the client code specifying the concrete implementation. The control in this instance that is being inverted is the act of the client obtaining the service.

米勒特,C(2010)。专业的ASP。NET设计模式。威利出版社,7-8。

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

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

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

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

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

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的实例中。

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

DI是IoC的一个子集

IoC means that objects do not create other objects on which they rely to do their work. Instead, they get the objects that they need from an outside service (for example, xml file or single app service). 2 implementations of IoC, I use, are DI and ServiceLocator. DI means the IoC principle of getting dependent object is done without using concrete objects but abstractions (interfaces). This makes all components chain testable, cause higher level component doesn't depend on lower level component, only from the interface. Mocks implement these interfaces.

以下是一些实现IoC的其他技术。