原文:http://www.cnblogs.com/Ivony/archive/2009/09/05/1561001.html
控制反转即IoC (Inversion of Control),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。”
老实说,我真的有一种天旋地转的感觉。。。。。
并不是因为这段定义的无稽,而是他的“经典性”,在搜索IoC和控制反转都能在前几个结果都看到这段“经典”的定义。我不由得觉得脊背一阵阵的发凉,真是见鬼了,原来我理解了这么多年的IoC是这么个意思。还好在我快要绝望的时候,终于看到了一篇厚道点的文章:
http://dotnetfresh.cnblogs.com/archive/2005/06/27/181878.html
废话不多说,谈谈个人对IoC的理解。话说这么多年来,我一直是这样理解IoC的。
当程序中存在组件A调用组件B的时候(或者说组件A控制组件B),组件A就会产生对组件B的依赖,那么B的变化就会影响到A的实现(比如说B接口变更)。但糟糕的是,组件A通常是主体框架,或者基础结构(如果读者有C语言编程的背景的话,不难理解所有的函数都要被main调用,而main却就是最根本的函数)。这个时候就会使得程序僵化,因为对任何细节的修改都可能会向上传播到基础框架的更改。这个时候就必须将控制(或依赖)的关系反转过来(所以控制反转和依赖倒置可以理解为是近义词)。
为什么会出现,或者叫做控制反转呢?我的猜测是这与传统的程序设计方式有关系。如果有C语言背景,就应该能理解main函数其实是一个总控制器,main函数定义主逻辑,其他函数定义各自的子逻辑,main函数调用(控制)其他函数协同完成一个任务。
由于最开始的程序设计采取的是自顶向下的方式,main函数处理总问题,然后将问题分解成为若干个小问题,交给不同的函数去处理。所以任何变更也只可能是自顶向下的。也就是说某一个问题的解决方案要做出修改,必然是从解决这个问题的函数出发,修改这个函数的实现,再修改他所调用(控制)的函数的实现。
当然到了后期,随着软件功能的复杂化,软件已经不是一个解决计算问题的程序,这种自顶向下的设计逐渐被淘汰,所以出现了僵化的问题。
后来,控制反转也被叫做依赖倒置。但在我的概念中,这两个东西只能算是近义词,依赖倒置只是从另一个角度来描述控制反转(或许更接近其本质)。后来出现的依赖倒置原则,则又与依赖倒置不同。依赖倒置原则不如被称为依赖关系原则更为贴切。至于后面的依赖注入,就跑得更远了。
最后谈谈面向接口编程的曲解,如果我的理解没有错的话,面向接口编程的接口,可不是C#和Java中的interface。面向接口编程的本意是,不应当依赖具体的实现编程,即面向组件提供的接口编程,而不是面向组件的实现逻辑编程。当然,如果一定要理解为就是针对interface而不是class编程也没有太大的问题,问题在于不管你是面向接口编程还是针对interface编程,都没有谁让你把所有的类都抽个接口出来吧。一个日志记录器,你可以抽象出ILogService没问题,但把记录的日志信息也给抽象出个ILogMessage就实在是令人费解了。完了这个ILogMessage还让某IoC容器自动创建,这恐怕就是广大SOA的实践中的真实案例。。。。
附一个IoC的例子:
设计一个软件,其中有一个功能模块是显示运行日志。传统的自顶向下的设计方法是,当前要解决的问题是显示日志,那么定义一个日志显示组件(控件):LogsShower,它要解决的问题有两个,一是显示出来,一个是获取日志,GetLogs。
我们可以看到这边的控制关系:
日志显示组件(控件) 获取 日志内容
或者说:
日志显示组件(控件) 依赖于 日志内容
这样的设计就会导致日志内容的任何更改都会导致日志显示组件的更改(事实上日志显示组件的更改又可能会广播到其上级组件),比如说日志格式、结构的更改,某些日志信息要标红,整粗。在这种情况下,最简单的解决方案就是IoC,控制反转。
即将上面的控制关系翻转过来:
日志内容 呈现到 日志显示组件(控件)
当然更彻底的解耦是日志呈现器监听日志记录器,并将日志内容通过日志呈现控件展现,这是后话,与IoC就离得远了。
继续搜索网上的文章,继续被雷:
依赖倒置(Dependency Inversion)和依赖注入(Dependency Injection)因为缩写同样是DI,所以被视为一个单词的不同翻译。依赖倒置原则,则又被解释为依赖倒置原理(一字之差)。
好在英文维基的解释就比较靠谱了:
Inversion of control, or IoC, is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to procedural programming.
In traditional programming the flow is controlled by a central piece of code. Using Inversion of Control this central control as a design principle is left behind. Although the caller will eventually get its answer, how and when is out of control of the caller. It is the callee who decides to answer how and when. The principle of Inversion of Control is also known as the Hollywood Principle. Inversion of Control as a design guideline serves the following purposes:
- There is a decoupling of the execution of a certain task from implementation.
- Every system can focus on what it is designed for.
- Every system does not make assumptions about what other systems do or should do.
- Replacing systems will have no side effect on other systems.