当第一次遇到控制反转(IoC)时,它可能非常令人困惑。

这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?


当前回答

在使用“控制反转”之前,你应该充分了解它的优点和缺点,如果你这样做,你应该知道为什么要使用它。

赞成的意见:

您的代码被解耦,因此您可以轻松地将接口的实现与其他实现交换它是针对接口而非实现进行编码的强大动力为代码编写单元测试是非常容易的,因为它只依赖于它在构造函数/setter中接受的对象,并且可以很容易地用正确的对象单独初始化它们。

欺骗:

IoC不仅会反转程序中的控制流,还会使其变得相当模糊。这意味着你不能再只读取代码并从一个地方跳到另一个地方,因为代码中通常存在的连接不再存在。相反,它在XML配置文件或注释中以及IoC容器的代码中解释这些元数据。出现了一类新的错误,即您的XML配置或注释错误,您可以花费大量时间来找出IoC容器在特定条件下向其中一个对象注入空引用的原因。

就我个人而言,我看到了IoC的优点,我非常喜欢它们,但我倾向于尽可能避免使用IoC,因为它将您的软件变成一个类的集合,这些类不再构成“真正的”程序,而只是需要通过XML配置或注释元数据组合在一起的东西,如果没有IoC,它就会崩溃。

其他回答

我已经读了很多关于这一点的答案,但如果有人仍然感到困惑,需要一个额外的“外行术语”来解释IoC,我的看法是:

想象一个父母和孩子彼此交谈。

没有IoC:

*家长:我问你问题时你才能说话,我允许你时你才能行动。

家长:这意味着,如果我不问你,你就不能问我你能不能吃饭、玩、上厕所甚至睡觉。

家长:你想吃吗?

孩子:没有。

家长:好的,我会回来的。等我。

孩子:(想玩,但由于家长没有问题,孩子什么都不会做)。

1小时后。。。

家长:我回来了。你想玩吗?

孩子:是的。

父级:已授予权限。

孩子:(终于可以玩了)。

这个简单的场景解释了控件以父级为中心。孩子的自由受到限制,高度依赖于父母的问题。孩子只有在被要求说话时才能说话,只有在获得许可时才能行动。

使用IoC:

孩子现在有能力提出问题,家长可以回答并获得许可。简单地说就是控制颠倒了!孩子现在可以随时提问,尽管在权限方面仍然依赖于家长,但他不依赖于说话/提问的方式。

从技术上解释,这与console/shell/cmd与GUI交互非常相似。(这是马克·哈里森的答案,排名第二)。在控制台中,您依赖于向您询问/显示的内容,如果不先回答问题,您无法跳转到其他菜单和功能;遵循严格的顺序流程。(编程上这就像一个方法/函数循环)。然而,有了GUI,菜单和功能就被布置好了,用户可以选择所需的任何内容,从而拥有更多的控制权和更少的限制。(以编程方式,菜单在选中并执行操作时具有回调)。

控制反转,(或IoC),是关于获得自由(你结婚了,失去了自由,你被控制了。你离婚了,你刚刚实现了控制反转。这就是我们所说的“脱钩”。好的计算机系统阻碍了一些非常亲密的关系。)更灵活(你办公室的厨房只供应干净的自来水,这是你想喝水时的唯一选择。你的老板通过安装一台新的咖啡机实现了控制反转。现在你可以灵活选择自来水或咖啡。)和更少的依赖性(你的伴侣有工作,你没有工作,你在经济上依赖你的伴侣,所以你受到控制。你找到了工作,你实现了控制反转。良好的计算机系统鼓励依赖。)

当你使用台式电脑时,你已经从(或者说,被控制)了。你必须坐在屏幕前看着屏幕。用键盘打字,用鼠标导航。一个写得不好的软件会让你更加痛苦。如果你把桌面换成笔记本电脑,那么你的控制就有点颠倒了。你可以轻松地拿着它四处走动。所以现在你可以用电脑控制你的位置,而不是由电脑控制。

通过实现控制反转,软件/对象消费者可以获得更多的软件/对象控制/选项,而不是被控制或拥有更少的选项。

考虑到上述想法。我们仍然错过了IoC的一个关键部分。在IoC的场景中,软件/对象使用者是一个复杂的框架。这意味着您创建的代码不是自己调用的。现在让我们来解释一下为什么这种方式对web应用程序更有效。

假设您的代码是一组工作人员。他们需要造一辆车。这些工人需要一个地方和工具(软件框架)来制造汽车。一个传统的软件框架就像一个有很多工具的车库。因此,工人们需要自己制定计划,并使用工具来制造汽车。造一辆车不是一件容易的事,工人们很难做好计划并进行适当的合作。一个现代化的软件框架将像一个拥有所有设施和管理人员的现代化汽车工厂。工人不必制定任何计划,管理者(框架的一部分,他们是最聪明的人,制定了最复杂的计划)将帮助协调,以便工人知道何时完成他们的工作(框架调用您的代码)。工人们只需要足够灵活地使用经理给他们的任何工具(通过使用依赖注入)。

尽管工人将项目管理的控制权交给了管理者(框架)。但有一些专业人士帮助是很好的。这就是IoC的真正来源。

具有MVC架构的现代Web应用程序依赖于框架来执行URL路由,并将控制器放置在适当的位置以供框架调用。

依赖注入和控制反转是相关的。依赖注入在微观层面,控制反转在宏观层面。为了完成一顿饭(实现IoC),你必须吃每一口(实现DI)。

“IoC”这个首字母缩略词和它所代表的名字似乎最让人困惑的是,这个名字太迷人了——几乎是一个喧嚣的名字。

我们真的需要一个名字来描述过程式编程和事件驱动编程之间的区别吗?好吧,如果我们需要的话,但我们是否需要选择一个全新的“比生活更大”的名字,它让人困惑而不是解决问题?

控制反转是将控制权从库转移到客户端。当我们讨论将函数值(lambda表达式)注入(传递)到控制(改变)库函数行为的高阶函数(库函数)中的客户端时,它更有意义。

因此,这个模式的一个简单实现(具有巨大的含义)是一个更高阶的库函数(它接受另一个函数作为参数)。库函数通过赋予客户端提供“控制”函数作为参数的能力来传递对其行为的控制。

例如,“map”、“flatMap”等库函数是IoC实现。

当然,例如,有限的IoC版本是布尔函数参数。客户端可以通过切换布尔参数来控制库函数。

将库依赖项(承载行为)注入到库中的客户端或框架也可以被视为IoC

为了理解这个概念,控制反转(IoC)或依赖反转原理(DIP)涉及两个活动:抽象和反转。依赖注入(DI)只是为数不多的反转方法之一。

要了解更多信息,您可以在此处阅读我的博客

这是怎么一回事?

这是一种让实际行为来自边界之外的实践(面向对象编程中的类)。边界实体只知道它的抽象(例如面向对象编程中的接口、抽象类、委托)。

它解决了什么问题?

在编程方面,IoC试图通过使单片代码模块化、解耦其各个部分并使其可单元测试来解决单片代码。

什么时候合适,什么时候不合适?

这在大多数情况下都是合适的,除非您有只需要单片代码的情况(例如非常简单的程序)