背景
流行的、时髦的东西,是特别容易识别的,因为你经常会碰见它们。芙蓉姐姐是这么让我给碰上的,今天想说的IoC也是这么给我碰上的。为了给自己的blog
带来点人气,老头子决定也开始走走流行路线。所以,今天我们就来动一动虽然没有芙蓉姐姐那么火,但是也算火的IoC。
Dependency Injection
IoC,全名叫做Inversion of Control,中文名叫控制反转。我对IoC比较全面的理解,来自于Martin Fowler的这篇文章。Martin Fowler是一位很务实的设计师,他说,IoC,叫做Dependency Injection,控制注入,要更准确一些。所以他的那篇文章的题目就叫Dependency Injection模式。但是,Ioc这个名字好象更火一些,所以,我还是沿用IoC这个名字好了。
老头子的目标,是用最短的篇幅来介绍IoC,并且告诉各位IoC其实是一个很旧的概念。这是老头子的兴趣所在。
铺垫
IoC模式,处理的是对象之间的依赖关系,这是为什么Martin先生说Dependency Injection更准确的原因。所以,我们先来看看对象依赖。
比如有两个对象cA和cB。其中cA依赖于cB。通常我们会看到这样的(伪)代码:
|
此后,cA对象的方法,就可以直接引用cB的实例b。
这样的代码并没有啥不妥,但是很明显,cA没有对接口进行依赖,而是依赖于cB的实现,这违反了对接口而不是实现编程的原则。这样做的不好之处在于:如果
cB的实现改变了,比如改用了另一个class,cA的代码就需要做出修改。虽然新的cB实现了和老的cB相同的接口,但是替换实现导致了使用者代码的更
改,这是不好的行为。也就是说cA被cB粘住了。
咋改
首先,改成这个样子:
|
这样改了之后,代码好看一些,心情也舒坦一些,但是,跟没改差不多。没有解决
根本问题,cA还是要负责创建cB实例,还是得依赖cB。但是,首先iB被分出来了,为下一步改进做好了准备。
iB
被分离出来,有一个隐含的好处。就是cA代码的修改,不必担心会使用到特定的cB实现暴露出来的公用方法,因为cA对cB的使用,已经被严格地限定在iB
所声明的方法集之内。这样一来,cB的实现,只要实现一个iB接口,其它的可以海阔天空。无需担心由于其它public方法被cA不小心引用而被cA粘
住。
解耦
接口被分离出来之后,剩下的,就是怎么将 new CB() 这个代码从cA里面拿出去。这就是说,怎么样把生成cB实例的任务交给其它对象去做。
其实问题的关键,就是怎么将iB实例设置到cA.b上面去。这有两种方法:
一种就是所谓的IoC。它通过cA对象的某个方法将一个作为外部参数传入进来的iB实例赋给cA.b。根据这个方法的不同,人们把IoC又分为三种类型,虽然在我看来它们是一回事。
还有一种,叫做Service Locator。就是把生成实例的任务,委托给一个周知的对象。把对其它对象的依赖,变成对该对象的依赖。这样的话,只要该对象能稳定,问题就不大了。
IoC
先说IoC的三种方法:
1。构造子注入,也叫type 3 IoC。实际上就是用构造函数来给cA.b赋值:
|
2。设值方法,也叫type 2 IoC。用一个set×××方法来给cA.b赋值:
|
3。接口注入,也叫type 1 IoC。cA开发一个接口,让框架通过该接口来给cA.b赋值:
|
这三种方式,形式有所不同,实质没啥区别。总之,都是提供接口让IoC容器来
调用,并通过这些暴露的接口来完成依赖的注入。因为这个赋值方法都是被IoC容器或外部应用调用,控制权从cA转移到外部框架去了。这就是控制反转名称的
由来。
使用IoC之后,应用代码大致如下:
|
做得好的IoC容器,可以将 new cB() 和 new cA() 的过程全部通过配置和容器来自动完成。
Service Locator
相对来说,Service Locator更简单直观一些,它的代码形如:
|
其中,serviceLocator可以实现为一个Singleton,或者作为一个静态成员传递给cA。因为它是周知的对象,这不是问题。
事实上
在我看来,IoC和ServiceLocator模式,并没有太大的差别。它们都将对象的实例化交给框架或第三方去完成,而当使用者需要对象的时候,对象
已经准备好。差别只在于,对于IoC模式来说,对象赋值是由外部代码完成的,使用者处于被动地位;而对于ServiceLocator来说,对象赋值是使
用者主动请求完成的,它处于主动地位。
对于这两种模式的比较,意义并不太大。到底使用哪一个,取决于个人的偏好。老头子在这里也就不多说什么了。
旧东西
我们只要回忆一下COM框架,就会知道IoC和ServiceLocator在那里其实都是旧东西。当微软把Automation再添加到COM架构中去
的时候,我们不能不感叹,COM是个好东西。憎恨微软当然没有问题,但依我看,对于微软,不服恐怕也是不行的。
至少,产品中处处体现出先进的设计理念的微软,没有象Java社群这样喜欢鼓噪新的概念。微软能够赢得最终用户的心,那也不是没有理由的。
预告
左手剑的下一击,我想讲讲同样火的AOP是个什么东西,以及,为什么说它也是个旧东西。