分享
 
 
 

IOC和Dependency Injection

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

介绍

其实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,再调用其方法实现,同样也消除了耦合关系

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有