面向对象的设计模式(九),适配器模式

 记得刚学Java SE的AWT(新版Swing)编程的时候,那个时候自己特别兴奋,因为学了那么久的Java了,没看到一点实在点的东西,觉得很没有成就感。后来学到Swing的时候,用它编写图形化界面,于是写了一个小小的计算器和其他简单的图形化程序。然而,在知道了Java的在图形化界面方面做的不是很好以后,心里有点失望,于是对Swing的热情也慢慢消退了。但是,我并不后悔花了点时间学Swing编程,因为在学习的过程中收获了喜悦,产生了一点小小的成就感,这些就已经够了。呵呵,话又说回来,Java的Swing编程还是值得了解或者学习一下的,因为用它来做一些演示还是挺好的。Java SE的那个Java的Applet(Java应用小程序)就简单了解一下知道Java有这么个小东西就行了,因为现在都基本宣布死亡了。

 上面又说了一些废话,不过,学习Swing也是我第一次接触适配器模式,知道有Adapter这个东西。后来,学了用Java作为开发语言的Android开发后,我才更加知道了Java的Swing没有白学,因为不仅可以用Swing编程学一些小的演示程序,而且使得我特别快就上手了Android开发,对Android中的ListView的Adapter模式也特别理解,不仅如此,不知道是不是之前学了Swing还是怎么的,对Android开发非常容易就理解了。到现在,自己可以独立开发Android了。但是,知识学不完,新技术不断,对Android还需要进阶,达到更高的一个层次,让我们一起努力,一起进步。下面,直接进入正题。

定义:把一个类的接口扩展成客户端所期待的另外一个接口,使得原来不能一起使用的两个类(一个接口和一个使用该接口的类)一起工作。

使用场景:

  1. 需要一个统一的输入接口,而输入端的类型不可知。这个时候,我们可以暴露一个接口适配器给客户端,让客户端自己定制。如Android的ListView的Adapter;

  2. 解决接口不兼容。使得原来的一些接口在新的场景下依旧可以用,而不必写新的接口。

优点:

  1. 更好的复用性。系统通过需要使用现有的类,而此类的接口不符合系统的需要,那么通过适配器模式就可以让这些功能得到更好的复用,而避免了写新的接口;

  2. 更好的扩展性。通过暴露给客户端一个适配器,让客户端自己定制功能,从而更好地扩展了系统的功能,如Android中既提供了SimpleAdapter,ArrayAdapter还提供了一个抽象适配器BaseAdapter让用户自己定制。

缺点:

  • 过多使用适配器,让系统杂乱不堪,不易于整体把握。如我们每次都为一个接口写一个是适配器(因为我们不需要实现该接口的所有方法)。

以生活中的裁缝铺为例

代码实现

衣服(接口)

/** * 衣服(接口) * @author lt * */
public interface Clothes { 

    public int getSize();
}

具体的衣服(客户端)

/** * 具体的衣服(客户端) * @author lt * */
public class Clothes1 implements Clothes{ 

    /** * 假设是180尺码 */
    @Override
    public int getSize() {
        return 180;
    }
}

裁缝铺(适配器)

/** * 裁缝铺(Adapter) * @author lt * */
public class TailorShop implements Clothes{ 

    private Clothes clothes;

    public TailorShop(Clothes clothes){
        this.clothes = clothes;
    }

    /** * 缩短五厘米 */
    @Override
    public int getSize() {
        return clothes.getSize()-5;
    }

    /** * 将衣服拉长5厘米 * @return */
    public int largen(){
        return clothes.getSize()+5;
    }
}

 这里的裁缝铺是把衣服缩短5厘米,当然,裁缝铺也可以将衣服变长,也不是固定就是5厘米哦,我们可以用一个参数来让客户端指定修剪长度,如我们将裁缝铺角色改造。

/** * 裁缝铺(Adapter) * @author lt * */
public class TailorShop implements Clothes{ 

    private Clothes clothes;
    /** * 要修剪的长度,正数为拉长,负数缩短 */
    private int ds;

    public TailorShop(Clothes clothes,int ds){
        this.clothes = clothes;
        this.ds = ds;
    }

    /** * 缩短五厘米 */
    @Override
    public int getSize() {
        return clothes.getSize()+ds;
    }
}

 当然,裁缝铺的功能不仅是改变衣服的尺寸哦,还有缝补衣服。这里就不扩展了,要扩展也就添加方法的事了。

测试(有图有真相):

public class Test { 

    public static void main(String[] args) {
        // 小明最近长了5里面,原来180,现在185了,但衣服还是180的
        Clothes clothes = new Clothes1();
        System.out.println("原来的衣服尺码:"+clothes.getSize());
        // 小明说拉长5厘米
        TailorShop tailorShop = new TailorShop(clothes,5);
        System.out.println("经过裁缝捕裁剪后衣服的尺码:"+tailorShop.getSize());
    }
}

结果(Run As):

《面向对象的设计模式(九),适配器模式》

裁缝铺修剪完后,小明顿时非常开心地穿起了原来自己喜欢但穿不了的衣服高兴地…

这个例子向我们演示了两个类(小明和衣服)原本不能一起工作,后来经过适配器(裁缝铺)修剪后又可以一起工作了(小明又穿上那件自己喜欢的衣服了)。其实,这个是对象适配器模式,当然还可以有类适配器模式,这两种模式的区别就是前者为类进行包裹封装,后者直接扩展类(继承)。下面再以一个例子结束本文的内容。

对于下面的这个接口:

public interface DemoInterface { 

    public void method1();
    public void method2();
    public void method3();
    public void method4();
    public void method5();
    public void method6();
    // ...
}

我们在使用这个接口的时候,我们每次都要实现6个或者更多的方法,如果我们不需要实现所有的方法,那么我们可以写一个这样的适配器

public abstract class DemoAdapter implements DemoInterface{ 

    @Override
    public abstract void method1();

    @Override
    public void method2() {
    }
    @Override
    public void method3() {
    }
    @Override
    public void method4() {
    }
    @Override
    public void method5() { 
    }
    @Override
    public void method6() {
    }
}

 除了我们必须要实现的method1外,其它不必实现的给个空的实现,不管他。下次,我们使用个适配器代替原来的接口,通常系统也会为我们提供这样的一个适配器,如果没有,我们可以自己写。

总结:

 任何的模式都有优缺点,适配器模式也不例外,如上面的抽象适配器就有一个明显的缺点,就是将一个接口替换成了抽象类,优点就是可以不用实现我们不需要实现的方法,而只关心我们必须要实现的那些方法,缺点就是由接口变成了类,使用可能会受限,因为java不支持多重继承,但可以实现多个接口。

    原文作者:宿罪
    原文地址: https://blog.csdn.net/ydxlt/article/details/50451040
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞