Java开发网 Java开发网
注册 | 登录 | 帮助 | 搜索 | 排行榜 | 发帖统计  

您没有登录

» Java开发网 » Design Pattern & UML  

按打印兼容模式打印这个话题 打印话题    把这个话题寄给朋友 寄给朋友    该主题的所有更新都将Email到你的邮箱 订阅主题
flat modethreaded modego to previous topicgo to next topicgo to back
作者 IOC和Dependency Injection
hesanxu512



发贴: 0
积分: 0
于 2004-10-26 00:40 user profilesend a private message to usersearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
最近网上这两个名词出现频率很高,于是抱着学习的态度读了Martin Flower的大作以及一些相关的文章,将心得与大家分享。

介绍
其实IOC模式并不是什么新的东西,它是一种很普遍的概念(或者说结构),GoF中的Template Method 就是IOC的结构。顾名思义,IOC即控制反转。著名的好莱坞原则:“Don’t Call us, We will call you”,以及Robert C. Martin在其敏捷软件开发中所描述的依赖倒置原则(Dependency Inversion Principle, DIP)都是这一思想的体现。Dependency Injection是Martin Flower对IOC模式的一种扩展的解释,下面我们从一个简单的实例开始。

考虑一个Button来控制Lamp的开和关。
拿到这个功能,我不假思索的画出了如下的类图,并写下了代码。

public class Button {
  private Lamp lnkLamp;
  public void poll() {
    lnkLamp.Turnon();
  }
}
但是马上发现这个设计的问题,Button类直接依赖于Lamp类,这个依赖关系意味着当Lamp类修改时,Button类会受到影响。此外,想重用Button类来控制类似与Lamp的另外一个对象则是不可能的。即Button控制Lamp,并且只能控制Lamp。
显然,我违反了“高层模块不应该依赖于底层模块,两者都应该依赖于抽象;抽象不应该依赖于具体实现,细节应该依赖于抽象” 这一原则(DIP原则)。
考虑到上述问题,自然地想到应该抽象出一个接口,来消除Button对Lamp的依赖,于是设计如下:

这样,我们倒置了Button对Lamp的依赖关系,使得Lamp依赖于SwitchableDevice接口,SwitchableDevice并没有依赖于Button类,任何知道如何操纵该接口的对象都可以控制Lamp。同时Button不只是可以控制Lamp,还可以控制同样实现SwitchableDevice接口的如Computer、Cell Phone等等。回头想想,这种做法好像似曾相识,拍拍脑袋,哦!这不是GoF策略(Strategy)模式吗?!正是,不经意间我就应用了设计模式(有点得意哦~~~~)。
现在再来考虑一个问题,刚才的做法虽然倒置了依赖关系,但是如果将Button作为一个应用程序来控制Lamp或者同样实现SwitchableDevice的Computer、Cell Phone等,则代码可能如下:
public class Button {
private SwitchableDevice lnkLamp;
public Button(){
lnkLamp= new Lamp();
}

}
也就是说Button和Lamp之间仍然存在《creates》这样的依赖关系。
为了解除这种依赖关系,首先看GoF能作些什么。显然,这个地方应该用Factory模式,将对象的创建交给Factory Class来处理,这样虽然解开了Lamp组件与我们应用程序Button之间的耦合关系,但是组件的创建仍然是显式的(explicitly),在组件更改时仍需要重新编译。
另外,通过一个ServiceLocator去look up实现类也是一种解除耦合的办法,看到这儿,你不禁会想EJB不就是这么实现的嘛,U are Right! Rod Johnson 在其大作J2EE without EJB中称这种方式为Dependency Look up,但这种方式也有其弊端,比如无法脱离容器环境,以及不利于Unit test等。
“Don’t Call us, We will Call you”,这个原则启示我们应该换一个思路,不应该在应用类中创建具体对象的实例,而是应该将具体对象实例的创建插入(plug)或者说注射(inject)到应用类中,这大概是依赖注射名称的由来吧。
这种实现方式需要在应用类以及调用组件之间建立一个assembler来解除两者之间的依赖,看起来与前面的方式没有太大区别,来看一下结构:

仔细查看会发现还是有比较大的不同,依赖关系是相反的,也就是说这个过程中依然倒置了依赖关系。Lamp通过Assembler将其创建过程注射到了Button中,从而消除了两者之间的耦合,增加了灵活性。
下面我们看一下具体的实现,在PicoContainer以及Spring中有着其不同的实现,分别代表了两种类型的Dependency Injection, 即Constructor Injection 和Setter Injection。
private MutablePicoContainer configureContainer() {
MutablePicoContainer pico = new DefaultPicoContainer();
pico.registerComponentImplementation(SwitchableDevice.class, Lamp.class);
pico.registerComponentImplementation(Button.class);
return pico;
}
然后可以通过MutablePicoContainer的getComponentImplementation方法获得实现类,调用其poll方法控制Lamp的开关,这样一来,两者之间的耦合通过PicoContainer提供的Assembler完全消除了。
Spring则通过一个XML格式的配置文件,将两者联系起来,使用时,通过ApplicationContext获得Button Bean,再调用其方法实现,同样也消除了耦合关系。

后面我将会关注Spring中IOC以及AOP的实现,学习的同时会将心得以Blog的形式与大家分享。

其中类图见附件,或者http://csdn.blog.net/hesan

classdigram.rar (20.78k)




话题树型展开
人气 标题 作者 字数 发贴时间
9748 IOC和Dependency Injection hesanxu512 2600 2004-10-26 00:40
8305 Re:IOC和Dependency Injection zerol 175 2004-10-26 00:57
8248 Re:IOC和Dependency Injection floater 212 2004-10-26 01:08
8348 Re:IOC和Dependency Injection Jove 74 2004-10-26 12:23
8193 Re:IOC和Dependency Injection hesanxu512 39 2004-10-26 12:51
8426 Re:IOC和Dependency Injection think 406 2004-10-26 19:38
8146 Re:IOC和Dependency Injection hesanxu512 93 2004-10-26 22:11
8734 Re:IOC和Dependency Injection floater 2357 2004-10-27 01:26

flat modethreaded modego to previous topicgo to next topicgo to back
  已读帖子
  新的帖子
  被删除的帖子
Jump to the top of page

   Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent
Copyright © 2002-2020 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号
客服电话 0592-8750026    客服信箱 714923@qq.com    客服QQ 714923