【2019.6.20 最后编辑】
要理解本文,请务必将实验1:框架设计者走一遍。
(实验的改进BubbleSort的步骤二,)针对抽象类型编程,表示为SortTest→IntSort<=BubbleSort
现在聚焦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这个没有什么价值术语,《设计模式》至少两次使用了它,[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不是什么技术,而是一种设计思想....”。是不是想死啊?
我没有兴趣批驳中文学院的文科生写的东西,我告诉你们正确的知识;哪些东西,一看就问题成堆。
我曾经为百度百科编辑了“控制反转”词条,又被反复改回去。不管那些人怎么搞,谁也不要采用它的垃圾解释。
------------------------------------------------------------
吐槽的要点:
在你使用God创建对象时,不过在调用一个创建对象的工具。更强大的Spring和God一样,一个工具箱!!!(重要的话,打3个!)所有框架都具有控制反转的这个特点,既然Spring DI容器与框架无关,因此Spring DI容器与Ioc无关。
说依赖注入(Dependency Injection)就说依赖注入呗,非得自称控制反转容器,难怪Martin Fowler要开骂:几位轻量级容器的作者说..."我的轿车是与众不同的,因为它有四个轮子"。
然而,提出DI的Martin Fowler,其实五十步笑一百步。他也错了,Spring DI容器根本不是轿车,它只有两个轮子。
框架编程/设计框架时,如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()?"男":"女");
}
}
并且大声地、傲娇地宣布:我编写了一个控制正转的程序。