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

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


当前回答

编程演讲

简单地说,IoC:它是使用接口作为特定对象(例如字段或参数)的一种方式,作为某些类可以使用的通配符。它允许代码的可重用性。

例如,假设我们有两个类:狗和猫。两者具有相同的品质/状态:年龄、体型、体重。因此,我可以创建一个名为AnimalService的服务类,而不是创建一个称为DogService和CatService的服务,它只允许在Dog和Cat使用IAnimal接口时使用它们。

然而,从务实的角度来看,它有一些倒退。

a) 大多数开发人员不知道如何使用它。例如,我可以创建一个名为Customer的类,我可以(使用IDE的工具)自动创建一个称为ICustomer的接口。因此,无论接口是否会被重用,找到一个充满类和接口的文件夹并不罕见。它叫做BLOATED。有些人可能会认为“也许在未来我们可以使用它”-|

b) 它有一些限制。例如,让我们讨论一下Dog和Cat的情况,我想添加一个仅针对狗的新服务(功能)。比方说,我想计算训练一只狗所需的天数(trainDays()),因为猫没用,猫不能训练(我开玩笑)。

b.1)如果我将trainDays()添加到服务AnimalService中,那么它也适用于猫,并且根本无效。

b.2)我可以在trainDays()中添加一个条件,它评估使用的类。但这将彻底打破IoC。

b.3)我可以为新功能创建一个名为DogService的新服务类。但是,这将增加代码的可维护性,因为我们将为Dog提供两类服务(具有类似的功能),这很糟糕。

其他回答

我觉得用这么多先前的答案回答这个问题有点尴尬,但我只是觉得任何答案都没有足够简单地说明这个概念。

所以我们开始。。。

在非IOC应用程序中,您需要对流程进行编码,并在其中包含所有详细步骤。考虑一个创建报告的程序,它将包含设置打印机连接、打印页眉、遍历详细记录、打印页脚、可能执行页面馈送等的代码。

在IOC版本的报告程序中,您将配置一个通用的、可重用的报告类的实例,即一个包含打印报告的过程流但其中没有任何详细信息的类。您提供的配置可能使用DI来指定报告应该调用哪个类来打印标题、报告应该调用什么类来打印详细信息行、,以及Report应该调用什么类来打印页脚。

因此,控制反转来自控制过程,而不是代码,而是包含在一个外部的、可重用的类(Report)中,该类允许您指定或注入(通过DI)报告的详细信息-页眉、详细信息行和页脚。

通过提供不同的细节类集,可以使用同一Report类(控制类)生成任意数量的不同报告。您通过依赖Report类来提供控件,而只是通过注入来指定报表之间的差异,从而实现了控件的反转。

在某些方面,IOC可以与驱动器备份应用程序相比较-备份总是执行相同的步骤,但备份的文件集可能完全不同。

现在具体地回答最初的问题。。。

这是怎么一回事?IOC依赖于一个可重用的控制器类,并提供针对当前问题的详细信息。它解决了哪个问题?防止您必须重述控制流程。什么时候使用合适,什么时候不合适?无论何时创建控制流始终相同且仅更改细节的流程流。在创建一次性自定义流程时,您不会使用它。

最后,IOC不是DI,DI也不是IOC——DI通常可以在IOC中使用(为了说明抽象控制类的细节)。

无论如何,我希望这有帮助。

维基百科文章。对我来说,控制反转就是将您按顺序编写的代码转换为委托结构。您的程序不是显式地控制一切,而是设置一个类或库,其中包含发生某些事情时要调用的某些函数。它解决了代码重复。例如,在过去,您可以手动编写自己的事件循环,在系统库中轮询新事件。现在,大多数现代API只需告诉系统库您感兴趣的事件,它会让您知道它们何时发生。控制反转是减少代码重复的一种实用方法,如果您发现自己复制了整个方法,只更改了一小段代码,可以考虑使用控制反转来解决它。在许多语言中,通过委托、接口甚至原始函数指针的概念,控制反转变得容易。它并不适合在所有情况下使用,因为这样编写时,程序的流程可能更难遵循。在编写可重用的库时,这是一种设计方法的有用方法,但除非它真的解决了代码重复问题,否则应该在自己程序的核心中谨慎使用。

假设你是一个物体。然后你去餐馆:

没有IoC:你要求“苹果”,当你要求更多时,你总是得到苹果。

与IoC:你可以要求“水果”。每次上桌你都可以得到不同的水果。例如,苹果、橙子或西瓜。

所以,很明显,当你喜欢品种时,IoC是首选。

IoC原则有助于设计松散耦合的类,使其可测试、可维护和可扩展。

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

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

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

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

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