要点:Inversion/倒置或反转,似乎具有天然的魔力,人们看到它就会想,哪里或什么东西倒置或反转了。

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

如果有人将1*5说成是1+1+1+1+1的控制反转/IoC,我都不反对,只要你喜欢。

请先阅读前两节。

应用程序对库函数的普通调用,和框架采用回调机制调用(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.黑箱框架”中,有一段话:

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. 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.【框架/framework的一个重要特征是,用户为了定制该框架而编写等方法,通常由框架自己调用,而非由用户的应用程序代码(来调用)。在协调和理顺应用程序活动上,框架通常扮演主程序的角色。这种控制的反转给予框架这样的威力——作为一个可扩展的骨架。用户所提供的方法,定制框架中定义的一般性算法,用于特定的应用。】

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

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

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

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

框架本身就是骨架,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,夫妻关系不变。I 0。IoC反映了某些应用程序员的失落心情:从自由自在变为受控于人。给大家一个印象深刻的IoC定义:

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

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

[1]参考:Ralph E. Johnson & Brian Foote,Designing Reusable Classes,1988,链接

http://www.laputan.org/drc/drc.html

原来的文字:

早在1988,Ralph E. Johnson与BrianFoote在文章Designing Reusable Classes中有一段话,成为控制反转(Inversion of Control)的来由[1]。

这段话从面向对象的角度解释框架对特点。按照Java排序测试框架,对这段文字的三句话进行具体地解读如下:

①作为框架的【SortTest→IntSort】的一个重要特征,用户(应用程序员)所定义的定制框架的方法即回调、BubbleSort中@Override soooooort(),应用程序员不会去调用它而是由框架中的SortTest调用。

用笔者的话说:框架【SortTest→IntSort】是骨架式方案,用户需要编写回调函数。回调函数由框架动态绑定。其实SortTest调用的是抽象类型IntSort的方法,框架才不管IntSort到底是什么具体类型的对象,不管该对象采用什么算法。C语言中不说定制框架,而是简单地说使用函数指针调用回调函数。

②SortTest是测试流程的主程序的角色,协调和理顺应用程序活动。

如果说术语IoC有什么意义,就在于它将SortTest这个所谓的“控制模块”或主程序的角色凸显出来。IoC为什么令人费解?在于很多人对控制模块给予了过分的解读。

③这种控制的反转给予【SortTest→IntSort】框架这样的能力,作为一个解决方案的骨架,应用程序员对框架中定义的一般性算法(通常是抽象函数)加以定制。

这里提出了IoC术语,它导致框架与IoC之间出现了如同鸡与蛋谁先的关系:

IoC在前?IoC使得框架能够成为骨架, IoC使得框架有威力吗?

框架在前?框架本身就是骨架,IoC不过是框架的一个特征定义(或解读),它主要说明框架与库函数的差别。

鸡与蛋谁先一个很无聊的问题。毫无疑问,框架本身就是骨架,IoC的各种说辞有些多余。但是,很多人包括Martin Fowler充分强调IoC的重要性,从IoC出发,针对控制和反转两个词加以推敲和讲故事。

严千钧:附:为什么说Martin Fowler不懂IoC

2 赞同 · 1 评论文章

2.IoC的“说文解字”

IoC说明了库函数和框架的区别,但是一些人喜欢通过“说文解字”理解控制反转。这里说一说:谁控制谁,控制什么,为何是反转,哪些方面反转了?

控制是指框架中的SortTest扮演主程序的角色或控制模块;控制什么?SortTest——骨架式方案的控制模块控制整个系统的流程。反转是指从应用程序员调用库函数,变成框架调用回调函数(C 语言中)或框架调用回调接口(Java中IntSort的抽象方法)。哪些方面反转了?应用程序和框架的调用方式不同了。

2.我曾经为百度百科编辑了“控制反转”词条,又被反复改回去。其摘要目前是这样的:

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

我没有兴趣跟这些人扯淡了。如果你清楚地知道库与框架的区别,你根本不需要控制反转这个术语。

因为流行 控制反转容器=依赖注入容器,然后,太多的烂人省略后面的“容器”两字,得到 控制反转=依赖注入;【yqj2065都不敢使用控制反转(Inversion of Control、IoC)这个术语了(本来穿衣服是正常的,裸体太流行了,我不敢穿衣服出门。嗯,就是这种赶脚。】

最后我想说,IoC除了让人糊涂之外,只能够用于装高大尚。问题是大量的论文——不知道有多少人写了多少IoC相关的文章,并为我国的科学研究贡献了数量。垃圾遍地呀。

3. 看看一段网上的话,不知道是什么逻辑。

Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”,那我们来深入分析一下:

  ●谁控制谁,控制什么:传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对 象的创建;谁控制谁?当然是IoC 容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。

  ●为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。

该文的意思:我抽烟,我依赖火。传统Java设计,我主动钻木取火(new);而IoC有打火机。谁控制谁?当然是打火机控制了火;控制什么?控制我对火的获取。为何是反转,哪些方面反转了?有反转就有正转,传统应用程序是由我主动钻木取火,就是正转;而反转则是由打火机来帮忙创建火及帮我点烟。哪些方面反转了?火的获取被反转了。

大神们的理论知识就说不一般。