“凿壁借光”的模式场景——设计模式系列谈之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类,它是一个由组合和继承或实现结合起来的类,实现了对已经存在的系统的使用,同时又不修改到已经存在的系统。
相关文章推荐
- “凿壁借光”的模式场景——设计模式系列谈之Adapter模式
- “凿壁借光”的模式场景——设计模式系列谈之Adapter模式
- “凿壁借光”的模式场景——设计模式系列谈之Adapter模式
- “凿壁借光”的模式场景——设计模式系列谈之Adapter模式
- “凿壁借光”的模式场景——设计模式系列谈之Adapter模式
- 设计模式总结篇系列:适配器模式(Adapter)
- C#设计模式系列:适配器模式(Adapter)
- 设计模式学习系列五:适配器模式(Adapter)
- 极速理解设计模式系列:6.适配器模式(Adapter Pattern)
- java设计模式(精通系列)-Adapter模式
- 设计模式系列--Adapter
- 极速理解设计模式系列:6.适配器模式(Adapter Pattern)
- iOS 设计模式系列:Adapter – 适配器模式
- JAVA设计模式系列之Adapter(适配器)-Java基础-Java-编程开发
- 研磨设计模式之适配器模式(Adapter)-场景问题
- C#设计模式系列:适配器模式(Adapter Pattern)
- 漂亮的Adapter模式-体会RecyclerView的设计实现
- 深入理解JavaScript系列(35):设计模式之迭代器模式
- 深入理解JavaScript系列(43):设计模式之状态模式
- 设计模式之美:Adapter(适配器)