【编程素质】设计模式-适配器模式(Adapter)

1,适配器模式(Adapter,包装器,Wrapper)

将一个类的接口,转换成客户期待的另一个接口。适配器类让原本不兼容的类合作无间。属于结构型模式

1)类适配器模式

①概念

Adapter类,通过继承 src类,实现 dst 类接口,完成src->dst的适配。

②举例

充电器的例子。
src类,有220V电压:

public class Voltage220 {
    public int output220V() {
        int src = 220;
        System.out.println("我是" + src + "V");
        return src;
    }
}

我们需要的des接口:输出5V。

public interface Voltage5 {
    int output5V();
}

适配器类:将220V(src)转换为5V(des)。

public class VoltageAdapter extends Voltage220 implements Voltage5 {
    @Override
    public int output5V() {
        int src = output220V();
        System.out.println("适配器工作开始适配电压");
        int dst = src / 44;
        System.out.println("适配完成后输出电压:" + dst);
        return dst;
    }
}

③优缺点

有局限性,des必须为接口才可以使用。(java是单一继承)

2)对象的适配器模式(常用)

①概念

基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承src类,而是持有src类的实例,以解决兼容性的问题。
即:持有 src类,实现 dst 类接口,完成src->dst的适配。

②举例

还是充电器例子:

public class VoltageAdapter2 implements Voltage5 {
    private Voltage220 mVoltage220;

    public VoltageAdapter2(Voltage220 voltage220) {
        mVoltage220 = voltage220;
    }

    @Override
    public int output5V() {
        int dst = 0;
        if (null != mVoltage220) {
            int src = mVoltage220.output220V();
            System.out.println("对象适配器工作,开始适配电压");
            dst = src / 44;
            System.out.println("适配完成后输出电压:" + dst);
        }
        return dst;
    }
}

这和我们常用的Android中的Adapter相同。

③优缺点

根据合成复用原则,组合大于继承,
所以它解决了类适配器必须继承src的局限性问题,也不再强求dst必须是接口。

3)接口的适配器模式(默认适配器模式,Default Adapter Pattern,缺省适配器模式)

①概念

当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。

②举例

AnimatorListenerAdapter类,就是一个接口适配器。
属性动画ValueAnimator类,通过addListener(AnimatorListener listener)方法添加监听器,常规写法:

 ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        valueAnimator.start();

如果不想实现Animator.AnimatorListener接口的全部方法,只想监听onAnimationStart,则如下写法:

  ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationStart(Animator animation) {
                //xxxx具体实现
            }
        });
        valueAnimator.start();

源码如下:
Adapter类:

public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
        Animator.AnimatorPauseListener {
    @Override
    public void onAnimationCancel(Animator animation) {
    }

    @Override
    public void onAnimationEnd(Animator animation) {
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
    }

    @Override
    public void onAnimationStart(Animator animation) {
    }

    @Override
    public void onAnimationPause(Animator animation) {
    }

    @Override
    public void onAnimationResume(Animator animation) {
    }
}

对应的src:

 public static interface AnimatorListener {
        void onAnimationStart(Animator animation);

        void onAnimationEnd(Animator animation);

        void onAnimationCancel(Animator animation);

        void onAnimationRepeat(Animator animation);
    }

4)三种适配器模式对比

类适配器,以类给到,在Adapter里,就是将src当做类,继承,
对象适配器,以对象给到,在Adapter里,将src作为一个对象,持有。
接口适配器,以接口给到,在Adapter里,将src作为一个接口,实现。

2,场景

①系统需要使用现有的类,而这些类的接口不符合系统的接口。
②要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
③需要一个统一的输出接口,而输入端的类型不可预知。

3,优缺点

1)优

①通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
②复用了现存的类,解决了现存类和复用环境要求不一致的问题。
③将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
④一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。

2)缺

对于对象适配器来说,更换适配器的实现过程比较复杂。

4,对比

1)适配器模式、装饰模式、外观模式对比

①意图
装饰者模式:不改变接口,但加入责任
适配器模式:将一个接口转成另一个接口
外观模式:让接口更简单

5,举例

①手机电源适配器
②ADO.NET的DataAdapter,是用作DataSet和数据源之间的适配器。DataAdapter通过映射Fill和Update来提供这一适配器。

6,Android中的适配器模式

1)概念

需要被适配的类、接口、对象,这些是我们已有的数据,简称 src(source);
最终需要的输出的数据:简称 dst (destination,即Target) ,适配器称之为 Adapter 。

一句话描述适配器模式: src->Adapter->dst,即src以某种形式(三种形式分别对应三种适配器模式)给到Adapter里,最终转化成了dst。

拿我们Android开发最熟悉的展示列表数据的三大控件:ListView,GridView,RecyclerView的Adapter来说,它们三个控件需要的是View(dst),而我们有的一般是datas(src),所以适配器Adapter就是完成了数据源datas 转化成 ItemView的工作。

2)举例

ListView的Adapter、GridView的Adapter、RecyclerView的Adapter

7,demo

package adapter;

public class Main_adapter {

    public static void main(String[] args){
        // 对客户端来说,调用的就是Target的Request()
        Target target = new Adapter();
        target.Request();
    }
}
package adapter;
/**
 * 客户期待的接口
 * 接口、具体的类、抽象类都可以
 * @author luo
 *
 */
public interface Target {

    public void Request();
}
package adapter;
/**
 * 适配器类,把原接口Adaptee转换为目标接口Target
 * 1,继承目标接口
 * 2,建立一个私有的原接口
 * 3,通过重写目标接口的方法,实际调用原接口的方法
 * @author luo
 *
 */
public class Adapter implements Target{

    private Adaptee adaptee = new Adaptee();

    @Override
    public void Request() {
        adaptee.SpecificRequest();
    }   
}
package adapter;
/**
 * 需要适配的类
 * @author luo
 *
 */
public class Adaptee {

    public void SpecificRequest(){
        System.out.println("This is a Specific Request");
    }
}

猜你喜欢

转载自blog.csdn.net/SunshineTan/article/details/80059824