什么是控制反转(Inversion of Control)

【2022.2 最后编辑】

要理解本文,请将实验1:框架设计者走一遍。IoC是OOD领域诸多概念的混乱之源。

1.2.4控制反转

应用程序对库函数的普通调用,和框架采用回调机制调用(C和Scheme语言)回调函数或动态绑定(Java语言) 回调函数,是有一定的差别,正是这种不同才有了工具箱与框架两个概念。完全没有必要使用其他术语如IoC去画蛇添足,如果仅仅多一个同义词问题也不大,但IoC是OOD领域诸多概念的混乱之源

控制反转/IoC出自于Ralph E. Johnson与Brian Foote早在1988写的文章《Designing Reusable Classes》[1],或许因为《设计模式》两次使用了它,参见[1.6.7设计应支持变化]和[5.10模板方法模式],该术语引起一些人的注意。

其中,Inversion/倒置或反转一词似乎具有天然的魔力,人们看到它就会想,哪里或什么东西倒置或反转了。1996,Robert C. Martin在一个专栏上发表的文章中,提出依赖倒置原则(Dependency Inversion Principle、DIP)使用了Inversion;当一些轻量级容器为它们的产品使用IoC容器作为噱头,而Martin Fowler或许受[GoF]的影响,或许因为IoC容器使用了IoC,他写了一篇有较大影响的文章IoC容器和依赖注入模式》,恰恰他对IoC认识迷糊,于是网络文章和Spring IoC容器相关书籍中到处充斥了关于IoC的胡言乱语。

1.IoC的出处

文章《设计可复用的类》写于1988,反映了当时人们对面向对象的认识,如认为“面向对象编程的主要动机是软件复用”;[GoF]关于框架的定义来自于该文章:框架是构成一类特定软件可复用设计的一组相互协作的类。在该文章“白箱Vs.黑箱框架”中,有一段话:[参考:Ralph E. Johnson & Brian Foote,Designing Reusable Classes,1988,链接http://www.laputan.org/drc/drc.html的来由。]

One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. [框架/framework的一个重要特征是,为定制框架而由用户定义的方法,常常由框架自己调用,而非由用户的应用程序代码(来调用)。]

The framework often plays the role of the main program in coordinating and sequencing application activity.[ 在协调和理顺应用程序活动上,框架通常扮演主程序的角色。]

 This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.[这种控制的反转给予框架这样的威力——作为一个可扩展的骨架。由用户提供的方法,将框架中定义的一般性算法加以定制给特定的应用。]

这段话从面向对象的角度解释框架的特点。按照本书前面章节的介绍,用户编写的回调函数,用户自己不会调用;框架作为通用的骨架式方案,处理了大量细节和工作流程,显然是“主程序的角色”。该文提到的inversion of control并没有任何解释,一笔带过。

按照实验2的Java排序测试框架,如果说术语IoC有什么意义,不过是它将SortTest这个所谓的“控制模块”或主程序的角色凸显出来。

这里出现的IoC隐隐地抬高了自己的身价:这种控制的反转给予框架这样的威力。真的是IoC使得框架具有威力吗?

2.无聊的控制和无聊的反转

框架本身就是骨架,IoC不过是对框架特征的一个可有可无的描述[框架本身就是骨架,只要知道框架是骨架式方案,IoC的各种说辞有些多余,因此IoC是个没有什么价值的术语;]。Inversion的魔力就在于看起来就不直观,显得高大上。于是库函数和框架的区别,被人为地解释得不知所云。很多人包括Martin Fowler充分喜爱IoC这个术语,通过“说文解字”介绍:谁控制谁,控制什么,为何是反转,哪些方面反转了?为了认清市面上关于IoC的胡言乱语【 中文学院的文科生写的东西】,这里推理一下。

  • 控制。从人的角度看,框架设计者控制了主程序的流程和暴露可扩展接口,他决定了主程序角色的类名为SortTest,有函数test(),他决定IntSort的接口为soooooort()。框架所体现的强制性,表现为应用程序员必须按照包中IntSort中的接口名编写自己的soooooort()回调函数。从程序的角度看,SortTest规定了测试什么、如何测试、流程如何等等,它作为骨架式方案的控制模块控制整个系统的流程。控制,不意味SortTest对其他模块有支配和限制的权利。模块之间,只谈依赖关系。
  • 反转。从人的角度看,主程序的编写者,从应用程序员变成了框架设计者;从程序的角度看,SortTest从上层的应用搬到了下层作为基础设施。但请注意:SortTest从应用程序中搬到框架中,连一个标点符号或空格都不变。不管在应用程序中还是在框架中,SortTest→IntSort,“依赖关系”完全一样。在应用程序中,SortTest应该/ought依赖IntSort;在框架中,SortTest必须/must依赖IntSort。
  • 永远不要问某个框架“哪些方面的控制被反转了呢?”这种愚蠢的问题。既然IoC是框架特征的一般性描述,每一种框架用途不一,不存在哪些方面反转的问题。JUnit是Java语言著名的单元测试框架,它的哪些方面的控制被反转了呢? Applet是Java小应用程序框架,它的哪些方面的控制被反转了呢?所有框架,“反转”了库函数单纯地被调。
  • IoC从面向对象的角度解释框架的基本特点和特征定义。而框架可以用C、Scheme或Java等各种范式的编程语言实现。从排序测试框架的C语言实现看,Ioc就是一个垃圾词汇。正如从C语言角度定义的回调函数一样垃圾。
  • 如果一个库不是框架而是工具箱,不要使用IoC讨论该工具箱。例如Spring依赖注入容器,绝大多数程序员没有定制它,没有写一个@Override函数,它仅仅是工具箱,与框架/Ioc无关。
  • 应用程序员调用工具箱,如同娶妻;应用程序员使用框架,如同当上门女婿。SortTest→IntSort,夫妻关系不变。IoC反映了某些应用程序员的失落心情:从自由自在变为受控于人。给大家一个印象深刻的IoC定义:

★控制反转/Ioc = = 数清楚回调接口soooooort()中o的个数。除此之外,IoC没有任何其他含义。

由于将在后续章节中介绍的很多内容与IoC存在关联,请在阅读[1.2.4抛弃DIP]、[1.3.3什么是好莱坞法则]、[2.2模板方法模式]和[3.2.3什么是依赖注入]时,回头看看本节。

这篇文章导致框架与IoC出现了如同鸡与蛋谁先的关系:

  • 是IoC使得框架能够成为骨架
  • 还是框架本身就是骨架,IoC不过是框架的一个特征定义(或解读)

从该文出发,针对控制和反转两个词加以推敲和讲故事,网络文章中有大量的对控制反转加以“说文解字”的文章),可以索源到Martin Fowler,他于2005年专门写了一篇博客《Inversion of Control》讨论这个术语,而造成较大影响的是他的文章IoC容器和依赖注入模式》,参见[3.2.3什么是依赖注入*]。令人遗憾的是,这个没有什么价值的术语,《设计模式》至少两次使用了它,参见[1.6.7设计应支持变化]和[5.10模板方法模式];Martin Fowler的IoC或许也受GoF的影响。这些使用案例,使得IoC的含义变得含混;或者说,他们使得没有太大价值的术语IoC变得高大起来,同时也使得IoC不知所云。

为了避免隔靴搔痒和云山雾绕的解释泛滥,这里给出IoC的一个定义:

★控制反转/Ioc,指框架扮演主程序的角色,以骨架式方案控制整个系统的流程(应用程序员提供支持代码)。反转是指主程序从应用程序员编写变成了框架设计者编写,或者说从应用程序员调用库函数,变成框架调用回调接口(而应用程序员小媳妇般地编写回调函数)。


遗留文字:

1.【2018.06.27】IoC我讲得很清楚了,一个毫无意义的垃圾术语!让你们做实验,让你们体会。考试时,还有很多人写:“IoC不是什么技术,而是一种设计思想....”。你们是不是想死啊?恼火得很。

2. 我曾经为百度百科编辑了“控制反转”词条,该词条又被改回去。晕了晕了,谁也不要采用它的垃圾解释其摘要目前是这样的:

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

3. Martin Fowler对IoC的解释,参见附:为什么说Martin Fowler不懂IoC,网络文章中有大量的对控制反转加以“说文解字”的文章,很多人针对控制和反转两个词加以推敲和讲故事,都源于Martin Fowler。

4.控制反转(Inversion of Control)仅仅是描述一种现象,或介绍框架的特点,仅此而已。如果你清楚地知道库与框架的区别,你根本不需要控制反转这个术语(本来IoC不过是一篇文章中的短语,被某些依赖注入容器自称为控制反转容器后,这个词控制反转IoC成为流行感冒一样的流行词,非常装逼)因为流行 控制反转容器=依赖注入容器,然后,太多的烂人省略后面的“容器”两字,得到 控制反转=依赖注入;【yqj2065不敢使用控制反转(Inversion of Control、IoC)这个术语了(本来穿衣服是正常的,裸体太流行了,我不敢穿衣服出门。嗯,就是这种赶脚。】

5 到处是这种错误的信息。网上搜索“控制反转”,你就知道,它们说:“控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,...Spring框架的核心“。

6.IoC与Spring DI容器无关

在你使用God创建对象时,不过在调用一个创建对象的工具。更强大的Spring和God一样,一个工具箱!!!(重要的话,打3个!)所有框架都具有控制反转的这个特点,既然Spring DI容器与框架无关,因此Spring DI容器与Ioc无关

说依赖注入(Dependency Injection)就说依赖注入呗,非得自称控制反转容器,难怪Martin Fowler要开骂:几位轻量级容器的作者说..."我的轿车是与众不同的,因为它有四个轮子"。

然而,提出DI的Martin Fowler,其实五十步笑一百步。他也错了,Spring DI容器根本不是轿车,它只有两个轮子

  • 14
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值