老头子耕种的土地 只有果实没有花朵

股票不知道你拥有它。当然,它也不在乎。

我们仨 左手剑 思无虑 岁月诗 扯股淡 他山玉 无主题
« 上一篇: Trackback 下一篇: Child of Our Time »
老头子 @ 2005-06-30 12:34

背景
       流行的、时髦的东西,是特别容易识别的,因为你经常会碰见它们。芙蓉姐姐是这么让我给碰上的,今天想说的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。通常我们会看到这样的(伪)代码:
       
       class cA...
               private cB b;
               public cA(){
                       b = new cB();
               }        

       此后,cA对象的方法,就可以直接引用cB的实例b。

       这样的代码并没有啥不妥,但是很明显,cA没有对接口进行依赖,而是依赖于cB的实现,这违反了对接口而不是实现编程的原则。这样做的不好之处在于:如果cB的实现改变了,比如改用了另一个class,cA的代码就需要做出修改。虽然新的cB实现了和老的cB相同的接口,但是替换实现导致了使用者代码的更改,这是不好的行为。也就是说cA被cB粘住了。

咋改
       首先,改成这个样子:
       
       interface iB ...
       class cB implements iB ...
       class cA ...
               private iB b;
               public cA(){
                       b = (iB)(new 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赋值:
       
       class cA ...
               public cA(iB ib){
                       b = ib;
               }        

       2。设值方法,也叫type 2 IoC。用一个set×××方法来给cA.b赋值:
       
       class cA ...
               public void setiB(iB ib){
                       b = ib;
               }        

       3。接口注入,也叫type 1 IoC。cA开发一个接口,让框架通过该接口来给cA.b赋值:
       
       public interface InjectiB{
               void injectiB(iB ib);
       }
       class cA implements InjectiB ...
               public void injectiB(iB ib){
                       b = ib;
               }        

       这三种方式,形式有所不同,实质没啥区别。总之,都是提供接口让IoC容器来调用,并通过这些暴露的接口来完成依赖的注入。因为这个赋值方法都是被IoC容器或外部应用调用,控制权从cA转移到外部框架去了。这就是控制反转名称的由来。

       使用IoC之后,应用代码大致如下:
       
               ......
               iB b = (iB)(new cB());
               cA a = new cA(b);
               或者
               cA a = new cA();
               a.setiB(b);
               或者
               cA a = new cA();
               a.injectiB(b);
               ......        

       做得好的IoC容器,可以将 new cB() new cA() 的过程全部通过配置和容器来自动完成。

Service Locator
       相对来说,Service Locator更简单直观一些,它的代码形如:
       
       class cA ...
               private iB b = serviceLocator.getInstance("iB");        

       其中,serviceLocator可以实现为一个Singleton,或者作为一个静态成员传递给cA。因为它是周知的对象,这不是问题。

事实上
       在我看来,IoC和ServiceLocator模式,并没有太大的差别。它们都将对象的实例化交给框架或第三方去完成,而当使用者需要对象的时候,对象已经准备好。差别只在于,对于IoC模式来说,对象赋值是由外部代码完成的,使用者处于被动地位;而对于ServiceLocator来说,对象赋值是使用者主动请求完成的,它处于主动地位。

       对于这两种模式的比较,意义并不太大。到底使用哪一个,取决于个人的偏好。老头子在这里也就不多说什么了。

旧东西
       我们只要回忆一下COM框架,就会知道IoC和ServiceLocator在那里其实都是旧东西。当微软把Automation再添加到COM架构中去的时候,我们不能不感叹,COM是个好东西。憎恨微软当然没有问题,但依我看,对于微软,不服恐怕也是不行的。

       至少,产品中处处体现出先进的设计理念的微软,没有象Java社群这样喜欢鼓噪新的概念。微软能够赢得最终用户的心,那也不是没有理由的。

预告
       左手剑的下一击,我想讲讲同样火的AOP是个什么东西,以及,为什么说它也是个旧东西。

最新评论

2005-07-01 00:43 网址: http://wenmangyu.blogms.com

我没阅读剩余部分,因为我看不懂。恩,写专业文字就是拽啊,我写不出这个,可要我写点卫生常识,横横,你就不成咯

就是为了一拽才写的。不然费那劲干嘛。


钟群

2005-07-02 12:09

对于最新的编程知识,偶是越来越out啦。最近公司人事打电话过来,说有另外一个项目急需数据库开发人员。做完这个华为的项目偶就准备换个项目组了。出差怕了...



老农

2005-07-04 20:33

反转控制和AOP都是好东西,不过AOP的编译需要额外的东西,这点比较讨厌. OO是纵向的,AOP是横向的,个人认为OO + AOP才是描述这个世界的最佳方法。可惜不知道为什么JDK中并不包含AOP。虽然AOP编译后能在JRE中运行。但是我担心用了AOP后会给用JDK作二次开发的人带来困惑。但是用AOP设计的经验不多,不能确定。有高人指点一下么? 在Spring中反转控制和AOP是两个大章,介绍的很详细.有兴趣的可以去买本来看看.

我觉得AOP没有加到JRE里面去,是因为性能的原因。又或者当时没有考虑到这一层。以后加不加,很难说。我看最好不要加。

评论 / 个人网页 / 扔小纸条
* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 


 

分类小组论坛
杂谈 , 娱乐、八卦 , 文学、艺术 , 体育 , 旅游、同城 , 象牙塔 , 情感 , 时尚、生活 , 星座 , 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定

捐款赞助
同道中人
· 管理通道
· 先生不死
· 名将左权
· 追我魂魄
· 读库
· 舵手
· KOKO
· 快乐朵朵
· 比客Allen
· samuel
站内搜索

订阅 RSS

0112562

歪酷博客