什么是 Inversion of Control (IoC)?

局限于英文水平和对软件工程“学术界”了解的浅薄,我对 Inverstion of Control —— 中文或许可以翻译成“反向控制” —— 的理解,总是停滞在一种似是而非的程度。我尝试通过搜索来学习,发现我能搜到的中文文章,都不能给我很大的帮助,有的在大谈特谈 Spring 框架如何如何;有的又说,想搞清楚 IoC,你先要理解 DIP …… ;也有的,干脆就说,所谓的 IoC 根本就是 DI。一时间,各种术语满天飞,越发让我觉得糊涂了。
不得已,我又开始搜寻英文资料,发现基本也是各种意见都有,但是无一例外都会指向一个地方,就是 Martin Fowler(马丁・福勒)的文章(很感谢国外这些博客的作者,都有良好的习惯,让人比较容易找到一个概念的发展脉络)。通过学习和对比各种国内的文章,我似乎对这个概念更加清晰了一些,不敢说全懂了,但是总算比以前明了了一点。特此记录。

我是一个PHP 程序员,一直使用 Yii 框架, 从 2.0 版本开始,就显式地出现了 DI 这个概念
,不怕丢人,我就是看不懂,不过就像大多数情况一样,看不懂也根本不会影响使用。不过,时不时遇到的时候,还是觉得萦绕心头,偶尔搜些资料看看,才知道了 IoC, 把 IoC 和 DI 联系在一起的人,是 Martin Fowler
中文版
),就算他不是第一个,但是极有可能是影响力最大的一个。
对我来说,DI 和 Service Locator 之外,又出现了一个新概念,就自然而然顺藤摸瓜去了解,没想到我非但没有更清楚,反而更糊涂了,继而又陆续看了很多资料,才又出现了一丝丝清明。

Inversion of Control

日常我们用到的词汇里面,有一种很常见的情况,就是除了这个词汇本身的内涵,在使用过程中,其外延不断扩展,有些甚至出现了引申意义,于是经常使得自然语言变得隐晦难明,给 NLP 带来困难的同时,人类自己也负担不轻。
这个经常被缩写成 IoC 的术语,如果翻译成中文的话,字面意义就是“反向控制”,但是,一般人读到四个汉字,基本是莫名其妙的。如果你使用了百度去搜索中文资料,看了一堆网友写的文章,相信你就离其真实含义更加遥远了(也包括本文)。
如果你在认真阅读本文的话,我试图传递给你的一个建议就是,不要相信所有的资料,包括本文。这样,或许你真的可以建立一些对这个概念的准确理解。这恐怕就是道可道,非常道吧,哈哈。

IoC 是什么?

关于 IoC 是什么,国内外网友也莫衷一是。有人说,这是一种设计模式,“设计模式” 是随着 GoF 的著作传开的一个专有名词,其实是描述了在面向对象软件设计(OOD)过程里,为了实现解耦与复用,软件工程界惯用的一些优秀的(起初识别了 23 个)类关系设计方案。每一个模式,都有其比较具体的场景,以及相对来说比较具体的设计模板,渐渐已经成为工程师交流的一套工具。从设计模式的特点来看,IoC 恐怕不能说是一种设计模式,因为,首先就没有比较具体的场景,也没有比较具体的设计模板,实现方案也有多种。所以,决不能称其为一种设计模式。
常见的一种说法,说 IoC 是一种设计原则,维基百科也如此定义。我想,这可能是比较接近事实的一个说法。但是,比起软件工程里其他一些更为显而易见的原则,比如 DRY 原则,SOLID 原则等等,IoC 的含义就显得模糊,尤其 SOLID 里面的 D 代表的依赖倒置(Dependency Inversion Principle,也叫 DIP),跟 IoC 看起来似乎又像一个意思。不少中文世界的博客,甚至就蠢蠢欲动地想要完成两者的替换,从而避免对其进行解释。
也有说 IoC 是一种实现。这可能是一种隐晦的表达。因为提及 IoC,不少人就要说 Spring,说起 IoC Container,这就使其变得非常具体,好像它是一个框架,或者甚至是一个类。我想,头脑稍微清明一点,不至于误解如此,但免不了,还是有人似是而非地如此认为。
Martin Fowler 在一篇词源追溯的文章里,对 IoC 的定义,是一种“现象”,或者说一种“特点”。介于他是这个领域最权威的专家和最早探讨这个概念的人之一,我个人比较倾向于相信他的话。其实我比较佩服的就是他的写作能力,他精挑细选地这两个词汇,避开了人云亦云的“Principle”或者“Pattern”,可以看出他的态度。

Inversion of Control is a common phenomenon that you come across when extending frameworks. Indeed it’s often seen as a defining characteristic of a framework.
—— bliki: InversionOfControl Martin Fowler

其实,在 Martin 老爷爷另一篇文章里,就是那篇著名地介绍了 Dependency Injection 的文章里,他也很巧妙地避免了混淆,那里他用了 IoC Container 和 DI 放在一起讨论,而不是 IoC 本身。IoC Container 和 IoC 不是一个概念,就算没有“雷锋”和“雷锋塔”区别那么大,其实也差不多了。