当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当第一次遇到控制反转(IoC)时,它可能非常令人困惑。
这是怎么一回事?它解决了哪个问题?什么时候使用合适,什么时候不合适?
当前回答
维基百科文章。对我来说,控制反转就是将您按顺序编写的代码转换为委托结构。您的程序不是显式地控制一切,而是设置一个类或库,其中包含发生某些事情时要调用的某些函数。它解决了代码重复。例如,在过去,您可以手动编写自己的事件循环,在系统库中轮询新事件。现在,大多数现代API只需告诉系统库您感兴趣的事件,它会让您知道它们何时发生。控制反转是减少代码重复的一种实用方法,如果您发现自己复制了整个方法,只更改了一小段代码,可以考虑使用控制反转来解决它。在许多语言中,通过委托、接口甚至原始函数指针的概念,控制反转变得容易。它并不适合在所有情况下使用,因为这样编写时,程序的流程可能更难遵循。在编写可重用的库时,这是一种设计方法的有用方法,但除非它真的解决了代码重复问题,否则应该在自己程序的核心中谨慎使用。
其他回答
所以上面的数字1。什么是控制反转?维护是它为我解决的首要问题。它保证我使用的是接口,这样两个类就不会彼此亲密。
使用温莎城堡这样的容器,它可以更好地解决维护问题。能够在不更改一行代码的情况下,将一个连接到数据库的组件替换为一个使用基于文件的持久性的组件,这是非常棒的(配置更改完成了)。
一旦你进入泛型,它会变得更好。想象一下,拥有一个接收记录并发布消息的消息发布者。它不在乎它发布了什么,但它需要一个映射器将记录中的内容转换为消息。
public class MessagePublisher<RECORD,MESSAGE>
{
public MessagePublisher(IMapper<RECORD,MESSAGE> mapper,IRemoteEndpoint endPointToSendTo)
{
//setup
}
}
我写过一次,但现在如果我发布不同类型的消息,我可以向这组代码中注入许多类型。我还可以编写映射器,将相同类型的记录映射到不同的消息。将DI与Generics结合使用使我能够编写很少的代码来完成许多任务。
哦,是的,存在可测试性问题,但它们比IoC/DI的优势更为次要。
我绝对喜欢IoC/DI。
3.当你有一个中等规模的项目时,它会变得更加合适。我会说,当你开始感到疼痛时,它就变得合适了。
我知道这里已经给出了答案。但我仍然认为,关于控制反转的一些基础知识必须在这里详细讨论,以供未来读者参考。
控制反转(IoC)建立在一个叫做好莱坞原理的非常简单的原理上。上面说,
不要给我们打电话,我们会给你打电话
这意味着不要去好莱坞实现你的梦想,如果你值得,那么好莱坞会找到你,让你的梦想成真。差不多颠倒了,嗯?
现在,当我们讨论IoC的原理时,我们常常忘记好莱坞。对于IoC来说,必须有三个要素,一个好莱坞,一个你和一个完成你梦想的任务。
在我们的编程世界中,Hollywood代表一个通用框架(可能由您或其他人编写),您代表您编写的用户代码,任务代表您希望用代码完成的任务。现在,你永远不会自己触发任务,而不是在IoC!相反,你已经设计好了所有的东西,这样你的框架就会触发你的任务。因此,您已经构建了一个可重用的框架,它可以使某人成为英雄或另一人成为恶棍。但这一框架始终处于主导地位,它知道什么时候该挑选某人,而某人只知道自己想要成为什么样的人。
这里将给出一个真实的例子。假设您想开发一个web应用程序。因此,您可以创建一个框架来处理web应用程序应该处理的所有常见事务,如处理http请求、创建应用程序菜单、服务页面、管理cookie、触发事件等。
然后你在你的框架中留下一些钩子,你可以在那里放置更多的代码来生成自定义菜单、页面、cookie或记录一些用户事件等。在每次浏览器请求时,你的框架都会运行并执行你的自定义代码,如果勾住了,然后将其发送回浏览器。
所以,这个想法非常简单。与其创建一个控制一切的用户应用程序,不如先创建一个可重用的框架来控制一切,然后编写自定义代码并将其连接到框架以及时执行这些代码。
Laravel和EJB就是这样一个框架的例子。
参考:
https://martinfowler.com/bliki/InversionOfControl.html
https://en.wikipedia.org/wiki/Inversion_of_control
控制反转是将控制权从库转移到客户端。当我们讨论将函数值(lambda表达式)注入(传递)到控制(改变)库函数行为的高阶函数(库函数)中的客户端时,它更有意义。
因此,这个模式的一个简单实现(具有巨大的含义)是一个更高阶的库函数(它接受另一个函数作为参数)。库函数通过赋予客户端提供“控制”函数作为参数的能力来传递对其行为的控制。
例如,“map”、“flatMap”等库函数是IoC实现。
当然,例如,有限的IoC版本是布尔函数参数。客户端可以通过切换布尔参数来控制库函数。
将库依赖项(承载行为)注入到库中的客户端或框架也可以被视为IoC
但我认为你必须非常小心。如果你过度使用这种模式,你会做出非常复杂的设计,甚至更复杂的代码。
就像这个例子中的TextEditor一样:如果你只有一个拼写检查器,那么可能真的没有必要使用IoC?除非你需要写单元测试之类的。。。
无论如何:要讲道理。设计模式是很好的实践,但不是圣经。不要把它粘在任何地方。
使用IoC,您不会对对象进行更新。您的IoC容器将做到这一点,并管理它们的生命周期。
它解决了必须手动将一种类型对象的每个实例化更改为另一种类型的问题。
如果您的功能将来可能会发生变化,或者根据中使用的环境或配置而有所不同,则使用此选项是合适的。