您的位置:首页 > 其它

“凿壁借光”的模式场景——设计模式系列谈之Adapter模式

2008-04-10 07:13 429 查看
                                                         “凿壁借光”的模式场景                                                ——设计模式系列谈之Adapter模式         在软件的开发过程中,我们经常会在已有的系统或类的基础上进行一些扩展。在扩展的过程中,有一些类可能直接为我们所用。还有一些类我们希望使用它们,但是不能直接为我们所用,我们也不能直接修改该类,原因可能是我们没有该类的源代码,无法做出修改;也可能是修改该类付出的代价太大。这就需要我们做出一定的工作来适应对那些类的使用。在常用模式中,有两种模式涉及到对原有代码的使用:Adapter模式和Visitor模式。本文将谈到Adapter模式,对于Visitor模式,后面也会有一个专题来讲倒它。记得有一个典故,叫“凿壁借光”。说的是一个读书人,由于家贫,没有钱买蜡烛,以至晚上无法学习。而他的隔壁的那一家人稍微好一些,能买一点蜡烛晚上使用。读书人呢,很想很想使用隔壁家的蜡烛,但他不能去借,因为没有还的;也不能讨,因为人家也不多。怎么办呢?读书人想出了办法:既然我不能把别人的蜡烛拿来,但是我可以想办法改变我家的一些东西,使得我能和他们共用蜡烛啊。于是读书人就通过改变自己家的状态——凿壁,使得蜡烛的光线透过来,而从达到了借光的目的。在模式中,我们的Adapter模式就是这种“凿壁借光”的模式。我们经常会希望使用这些原有的类,有些可以直接使用;有些由于某种原因,可能是功能的原因等等,我们不能直接使用该类,而需要“凿壁”——我们做一些额外的工作,来使得我们“借光”——能够使用该类。在什么情况下使用Adapter模式呢?综合起来,有以下三种情况:第一,   能够直接使用已有的类。我们假设系统已经存在一个类:WhatIHave类,在这个类里我们有全部或部分的方法需要拿来使用。具体说需要在一个实现了WhatIWant接口的类里使用。Public class WhatIHave{        public void f(){……}        public void g(){……}}这是我们已经存在的类。Public interface WhatIWant{        public void h();}这是我们希望实现的类的接口。下面我们来使用Adapter模式来实现WhatIWant接口,同时该实现也拥有WhatIHave类的功能。Public class WhatIDo implements WhatIWant{        private WhatIHave wih = new WhatIHave();        public void f()        {               wih.f();}        public void g()        {               wih.g();}public void h(){       ……}}对WhatIDo类来说,它的情况比“凿壁借光”里的那个读书人境况好一些,它可以把别人的东西直接拿来使用,所以应用Adapter模式的WhatIDo类实现了WhatIWant接口,然后又把WhatIHave类的对象作为它的一个属性,从而达到对WhatIHave类的功能的使用的目的。上面的一个最最简单的对Adapter模式的使用。可以看出,Adapter模式无非是综合了类的两种再生模式:继承或实现、组合。在上面的那个简单的例子中,Adapter模式使用了组合来达到实用已经存在的类的功能的目的。第二,   不能够直接使用已有的类。假设我们系统存在一个Light类,可能就是上面那个读书人希望得到的蜡烛光吧,其代码如下:public class Light{        public void turnOn()        {               ……               System.out.println(“The light is on,you can do anything……”);}public void turnOff(){       ……       System.out.println(“Be careful!the light is power off……”)}}现在读书人通过“凿壁”已经“借到光”了,但是他现在又有了新的需求,就是希望能控制那只蜡烛,“我想让它亮的时候它就亮,想让它灭的时候它就灭”。读书人自己有一个开关,就是Button类。他首先想到的方法是把隔壁家的蜡烛的控制也接到我的开关上,直接来控制那个蜡烛,如下:public class Button{        private Light light = new Light();        public void pressOn()        {               light.turnOn();}public void pressOff(){       light.turnOff();}}读书人很高兴,他用了一段时间,但是新的麻烦上来了,他只有这么一个开关,他还想用这个开关做做别的事呢,比如他家的窗户被他设计了一个自动开闭的机关,他也想控制一下那个机关。他就发现不行了,因为Button类只依赖Light类,没有办法加入控制机关的功能。读书人就想,没关系啊,我首先创建一个接口,让Light类和机关都来实现我的接口不就行了。可隔壁家说了,“这是我们的Light类,你不能随意处理”。读书人连忙赔笑道,“您放心,不会的,不会的”。他到底是有学问的人,眼睛一轮,计上心来,暗道,那我就不改变你的东西,改变我的东西,用Adapter模式。绝大多数的模式都离不开接口,Adapter模式也一样,读书人首先创建了一个接口,如下:public interface Switch{        public void turnOn();        public void turnOff();}读书人心想,有了这个接口,我的机关就有着落了,它肯定是要实现这个接口的,先不管它,还是想想怎么把Light类的开关“借”过来吧。接着,读书人创建了一个LightAdapter类,如下:public class LightAdapter implements Switch{        private Light light = new Light();        public void turnOn()        {               light.turnOn();}public void turnOff(){       light.turnOff();}}读书人一击掌,心想,让LightAdapter类去依赖Light类吧,反正我的Button类是不能依赖Light类的,它要依赖Switch接口,这样我的机关只要实现了Switch接口,就能被我的Button类控制了;同时,LightAdapter类也实现了Switch接口,则Light类也可以间接被我的Button类控制了。以下是他修改后的Button类:public class Button{        private Switch switch;        public Button(Switch switch)        {               this.switch = switch;}public void pressOn(){       this.switch.trunOn();}public void pressOff(){       this.switch.turnOff();}}在这里,Adapter模式十分简单:如果客户端要使用某一个已经存在的不能被修改的类,那么让Adapter类(上面的LightAdapter类)去依赖那个已经存在的类;而客户端只依赖Adapter类的接口(上面的Switch类)。第三,   客户端协议和已经存在类的协议不一致不久,隔壁家换了一种新型的蜡烛,这种蜡烛能调节光线的亮度,如下:public class Light{        private int state;        public Light(int state)        {               this.state = state;}public void turnLow(){       System.out.println(“The state is 1,the light is low……”);}public void turnMedium(){       System.out.println(“The state is 2,the light is medium……”);}public void turnHigh(){       System.out.println(“The state is 3,the light is high……”);}public void turnOff(){       System.out.println(“The state is 0,the light is off……”);}public int getState(){       return this.state;}}能控制蜡烛的亮度,读书人当然高兴啊。可是他又遇到了麻烦:他的开关只能控制开和关,他又不能将开关改造成多路开关,因为他的很多其他的器件的控制只有开和关,如果开关改了,那么对其他器件的控制势必出现混乱。这时候,简单的使用Button类对Light类进行组合肯定不行了,读书人想,我还是借助于Adapter模式吧。Public class MultiWayAdapter implements Switch{        private Light light;        public MultiWayAdapter(Light light)        {               this.light = light;}public void turnOn(){       int state = this.light.getState();       switch(state)       case 1 : this.light.turnLow();       case 2 : this.light.turnMedium();       case 3 : this.light.turnHigh();}public void turnOff(){       this.light.turnOff();}}在这个例子里,Adapter类除了实现前面Adapter模式的功能,还担负着另外一个职责:修改已经存在的类的协议,以它满足我们所要求的协议。在Light类里,它有turnLow()、turnMedium()、turnHigh()、turnOff()等功能,而我们的客户端只有turnOn()和turnOff()的功能,我们通过MultiWayAdapter类,将Light类的四种功能转化为Button类所需要的两种功能。好了,上面我们通过“凿壁借光”的读书人的种种遭遇,来说明了我们为什么要使用Adapter模式,或者说使用Adapter模式的好处。下面我们来谈一谈Adapter模式的几种不同的使用方式。还是一个简单例子开始。已经存在的类:public class WhatIHave { public void f() {        System.out.println("It's f() function..."); } public void g() {        System.out.println("The g() function......"); } }我们所希望的接口:public interface WhatIWant { public void f(); public void g(); public void h(); }Adapter类:public class Adapter implements WhatIWant{ private WhatIHave wih; public Adapter(WhatIHave wih) {        this.wih = wih; } public void f() {        this.wih.f(); } public void g() {        this.wih.g(); } public void h() {        System.out.println("aha,h() function..."); } }使用方法一:public class WhatIUse { public void op(WhatIWant wiw) {        wiw.f();        wiw.g();        wiw.h(); } }这种方法使得客户端依赖接口,而不是具体的实现,具有很强的扩展性。测试代码如下:WhatIHave wih = new WhatIHave();        WhatIWant wiw = new Adapter(wih);        WhatIUse wiu = new WhatIUse();        wiu.op(wiw);测试结果如下:[align=left]It's f() function...[/align][align=left]The g() function......[/align]aha,h() function...使用方法二:public class WhatIUse2 { public void op(WhatIHave wih) {        WhatIWant wiw = new Adapter(wih);        wiw.f();        wiw.g();        wiw.h(); } }这种方法依赖于具体类WhatIHave,它的好处是客户端对Adapter类及其接口可以毫无关心。测试代码如下:WhatIHave wih = new WhatIHave();        WhatIUse2 wiu2 = new WhatIUse2();        wiu2.op(wih);测试结果如下:[align=left]It's f() function...[/align][align=left]The g() function......[/align]aha,h() function...使用方法三:public class Adapter2 extends WhatIHave implements WhatIWant { public void h() {        System.out.println("hehe,h() function is comingl...");  } }这是改变了Adapter类,让它继承了WhatIHave类,这样的好处当然是Adapter2类实现起来比原来的Adapter类简单得多,但是它同时拥有继承的弱点。测试代码如下:WhatIWant wiw2 = new Adapter2();WhatIUse wiu = new WhatIUse();        wiu.op(wiw2);测试结果如下:[align=left]It's f() function...[/align][align=left]The g() function......[/align]hehe,h() function is comingl...还有一些关于使用Adapter模式的其他方法,在这里就不再阐述了。Adapter模式的关键在于实现Adapter类,它是一个由组合和继承或实现结合起来的类,实现了对已经存在的系统的使用,同时又不修改到已经存在的系统。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: