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

news/2024/7/8 3:04:27
                                                         “凿壁借光”的模式场景
                                                ——设计模式系列谈之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);
测试结果如下:
It's f() function...
The g() function......
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);
测试结果如下:
It's f() function...
The g() function......
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);
测试结果如下:
It's f() function...
The g() function......
hehe,h() function is comingl...
还有一些关于使用Adapter模式的其他方法,在这里就不再阐述了。Adapter模式的关键在于实现Adapter类,它是一个由组合和继承或实现结合起来的类,实现了对已经存在的系统的使用,同时又不修改到已经存在的系统。




http://www.niftyadmin.cn/n/3653695.html

相关文章

我没有使用Spring

我没有使用Spring作者: Bob Lee在这里,Spring指的是Spring开发框架,一种依赖注入容器的实现。首先,我声明我没有一点冒犯Rod的意思(你是个优秀的人)。但是坦白地说,我不能狂热的追随您的开发框架…

对commons fileupload组件的简单封装

对commons fileupload组件的简单封装在上一篇文章《利用Jakarta commons fileupload组件实现多文件上传》中,我介绍了commons fileupload组件的基本原理和实现方法。但是在实际操作中,我们需要分析每个FileItem,然后从该FileItem中读取该控件…

java读取pdf文件内容

java读取pdf文件内容 在java中要读取pdf文件内容,我们可以借助第三方软件实现。常用的是xpdf,本文就简单介绍在linux下如何安装xpdf,及在java中如何利用xpdf读取pdf文件内容。一.安装xpdf在fc系列下,不用安装,…

使用iText操作pdf文件

使用iText操作pdf文件前段时间写过一篇文章《java读取pdf文件的内容》,pig0045给我回复,说可以直接利用iText搞定,我很感激,因为以前处理pdf文件并不多,对这块相关组件并不了解,pig0045给我介绍了一个新的方…

利用脚本启动java程序

利用脚本启动java程序今天在工作中,需要写一个shell脚本,启动一个socket程序,从而模拟短信网关。查了一些资料,终于搞定了,现在记录一下,方便大家查阅。为了说明使用方法,我们就用最简单的程序来…

JMF捕获音频和视频(转贴)

1. 1、捕获媒体数据的步骤:l 查询CaptureDeviceManager,来定位你需要使用的媒体采集设备。l 得到此设备的CaptureDeviceInfo实例。l 从此CaptureDeviceInfo实例获得一个MediaLocator,并通过它来创建一个DataSource。l 用此DataS…

巧妙使用spring对commons fileUpload的包装

巧妙使用spring对commons fileUpload的包装以前简单使用过spring的文件上传,当时没深入研究,以为spring只能实现单个文件的上传,所以后来就又大致学了下commons fileupload组件。在最近的工作中,有同事提出,他在把comm…

技术高手的13条原则

“大学生眼高手低”似乎并不是个别现象,象牙塔内生长的孩子们很多人忽略了外界的行情,总以为考试的高手就是未来职场上的“抢手货”。企业在市场经济的大环境下,注重的更多是能力而非学历。一技之长,总是企业HR所青睐的。很多学生…