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

【2019.6.20 最后编辑】

要理解本文,请务必将实验1:框架设计者走一遍。

(实验的改进BubbleSort的步骤二,)针对抽象类型编程,表示为SortTest→IntSort<=BubbleSort

1.1.3控制反转

现在聚焦SortTest,它是测试流程的控制模块。当应用程序员编写SortTest,他感觉一切都在他的(代码的)控制之下。也就是说,应用程序员决定控制模块SortTest要干什么、测试程序的流程是什么;最为关键的是,应用程序员还决定SortTest依赖的类型名为IntSort、IntSort的接口名为sort(),等等。

考虑编写SortTest的另外一种场景。假设SortTest中提供了完善的测试逻辑——如比较被测算法与JDK排序算法的一致性(保证排序正确)、大规模测试的时间复杂度的图形绘制等等重要而有用的代码,因此希望SortTest能够被广泛地复用。或者说,SortTest和IntSort是老师预先提供的测试工具并打包提供给学生,学生随后编写自己的某种排序算法并被要求复用该包。

这种场景,可以称为对排序测试的框架的复用。

框架打包表示为【SortTest->IntSort】,然后应用程序员编写Main->【SortTest->IntSort】<=BubbleSort

对比两种情况——编写应用程序使用框架控制反转(Inversion of Control,IoC)[1]反映了某些应用程序员的失落心情:从自由自在变为受控于人。当SortTest作为上层模块(应用程序员编写SortTest),应用程序员决定测试逻辑、决定IntSort中的接口名字如sort();当SortTest和IntSort作为下层模块,应用程序员需要按照IntSort中的接口名编写@Override方法(编写的该方法,被称为回调函数),如果框架设计者为接口命名为soooooort(),应用程序员编写回调函数时,要注意数清楚o的个数

3.什么是IoC

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

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

结合排序测试框架,可知:(1)在复用排序测试框架时,用户(应用程序员)定义的定制框架的方法,即BubbleSort中@Override soooooort(),应用程序员不会去调用而是由框架中的SortTest调用(其实,SortTest调用的是抽象类IntSort的方法,框架才不管IntSort对象到底叫什么,采用什么算法)。(2)SortTest是测试流程的主程序的角色,协调和理顺应用程序活动(编程中,程序员通常不关注这个主程序的角色);(3)框架作为一个可扩展的骨架,它完成对整个任务的主程序的角色不是正常的吗,不可能要应用程序规定测试流程吧?

所以,控制反转(Inversion of Control)的本意,指SortTest代表框架规定了解决方案的骨架,而应用程序员提供@Override soooooort()这种支持代码。所以,控制反转就是说框架控制一切,应用程序员提供支持代码。然而,很多人喜欢针对控制和反转两个词加以推敲和演义。因此笔者给出一个演义:

控制反转/Ioc,即框架控制一切,应用程序员提供支持代码。IoC反映了某些应用程序员的失落心情:从自由自在变为受控于人。IoC描述了一种现象:软件设计决定的控制权,由应用程序员转移到框架设计者手中。除此之外,IoC没有任何其他含义。

  • 为什么说IoC反映了某些应用程序员的失落心情?因为作为框架的设计者,他不会有任何受控于人的感觉,他和应用程序员自由编程时一样,自由自在;他界定主程序的角色SortTest,他决定IntSort的接口为soooooort();在框架的设计者看来,从来就不存在控制的反转。换言之,IoC是应用程序员专用的酸溜溜的词汇, 因此是一个没有什么价值的术语。
  • 可以使用C语言、Scheme语言或Java语言等各种编程语言设计框架,因此,控制反转不是面向对象的专用名词,更不是与对象创建相关的某些工具的专用名词。在程序设计实践中,程序员通常不会在意SortTest这个所谓的“控制模块”,也不会在意控制反转概念,而是更关注IntSort所表示的概念和技术——回调机制。
  • 特别地,控制反转从来没有暗示程序中哪个模块要控制另外的模块。不论是应用程序中还是框架中,模块之间的“依赖关系”完全一样,SortTest依赖IntSort。
  • 记住,永远不要问“哪些方面的控制被反转了呢?”这种愚蠢的问题。因为框架的设计者从来不考虑这种问题,他们不谈控制,没有反转。

令人遗憾的是,IoC这个没有什么价值术语,《设计模式》至少两次使用了它,[1.6.7设计应支持变化]和[5.10模板方法模式];而且,Martin Fowler在其著名文章Inversion of Control Containers and the Dependency Injection pattern中 ,也使用了该术语。这些使用案例,使得IoC的含义变得含混;或者说,他们使得没有太大价值的术语IoC变得高大起来,同时也使得IoC不知所云。

批驳GoF,参见[1.4.2什么是好莱坞法则];批驳Martin Fowler,参见[3.2.1God VS. Spring]。

关于框架的详尽介绍,参见[1.3.1分层]。


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

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


 

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

我没有兴趣批驳中文学院的文科生写的东西,我告诉你们正确的知识;哪些东西,一看就问题成堆。

我曾经为百度百科编辑了“控制反转”词条,又被反复改回去。不管那些人怎么搞,谁也不要采用它的垃圾解释

------------------------------------------------------------

吐槽的要点:

  1. 框架/framework是在底层中定义的一个骨架式方案,处理各种应用中面临的共同的底层细节;骨架式方案就需要应用程序员打小工。
  2. 控制反转/Ioc,即框架控制一切,应用程序员提供支持代码。IoC反映了某些应用程序员的失落心情:从自由自在变为受控于人。IoC描述了一种现象:软件设计决定的控制权,由应用程序员转移到框架设计者手中。除此之外,IoC没有任何其他含义。
  3. 什么是反转?讨论反转不反转,需要你有两次体验,对比两种情况。在实验1:框架设计者中,你就会遇到两种场景:应用程序和框架
  4. 什么是控制?在IoC中,你“可以”将SortTest称为控制模块。一般地,控制模块就是一个通常意义上的Client,它依赖抽象类型IServer,即C-S结构。所以,“控制模块”的称呼,不要也罢。IoC中,所谓控制,指设计决定的控制权,设计决定的控制权,设计决定的控制权。解读IoC,不要在“控制”上异想天开,说些不知所云的话。
  5. 总之,控制反转(Inversion of Control)仅仅是描述一种现象,或介绍框架的特点,仅此而已。如果你清楚地知道库与框架的区别,你根本不需要控制反转这个术语(本来IoC不过是一篇文章中的短语,被某些依赖注入容器自称为控制反转容器后,这个词控制反转IoC成为流行感冒一样的流行词,非常装逼)
  6. 因为流行 控制反转容器=依赖注入容器,然后,太多的烂人省略后面的“容器”两字,得到 控制反转=依赖注入;【yqj2065不敢使用控制反转(Inversion of Control、IoC)这个术语了(本来穿衣服是正常的,裸体太流行了,我不敢穿衣服出门。嗯,就是这种赶脚。】
  7. 到处是这种错误的信息。看看百度百科、360百科或网上搜索“控制反转”,你就懂了,它们说:“控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,...Spring框架的核心“。

 

3.IoC与Spring DI容器无关

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

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

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

 

4.不要使用你不懂的术语——说Martin Fowler呢

 

框架编程/设计框架时,如Java Applet框架定义各种回调接口如 init()等生命周期方法,应用程序员则给出@Override init()等回调(即回调函数)。因此,yqj2065直接使用回调等术语,不太需要这个说明框架的特点的术语IoC。

按照Martin Fowler的IoC解读,很多人编写了几年SSH( struts+spring+hibernate)应用程序,如果你觉没有什么成就感的话,你可以写一个Helloworld级别的程序,如:

package tips;
import static tips.Print.*;//替代System.out.println()等
import java.util.Scanner;
/**
 * @author yqj2065
 * @version 0.1
 */
public class InputDemo{
    public static void demo() {
        Scanner scanner = new Scanner(System.in);
        p("请输入姓名: ");
        pfln("Hello! %s!", scanner.next());
        p("请输入年龄: ");
        pfln("OK! %d!", (int)scanner.nextDouble());
        p("是男生吗?(true or false): ");
        pfln("ye! %s!", scanner.nextBoolean()?"男":"女");
    }
}

 

并且大声地、傲娇地宣布:我编写了一个控制正转的程序。

你可能感兴趣的:(#,面向对象设计(Java))