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

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

1)定义

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

2)参与者

在这里插入图片描述

① Adaptee(适配者类)

需要被适配的类、接口、对象,这些是已经存在的形式;

② Target (目标抽象类)

最终需要的形式

③ Adapter(适配器)

转换器,对Adaptee和Target进行适配。适配者类的三种形式分别对应三种适配器模式,类适配器、接口适配器、对象适配器。

3)场景

  1. 系统需要使用现有的类,而此类的接口不符合系统的需要。
  2. 要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
    (这些源类不一定有一致的接口。)
  3. 需要一个统一的输出接口,而输入端的类型不可预知。
    (比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)

注意事项:适配器不是在详细设计时添加的,而是解决正在服役的项目的问题。即组合模式的使用是在设计、开发完成后,发现现存类和复用环境不一致的问题才使用的。

4)举例

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

5)Android中的适配器模式

ListView的Adapter、GridView的Adapter、RecyclerView的Adapter都使用了适配器模式。

对于ListView,GridView,RecyclerView的Adapter来说,它们三个控件需要的是View(Target ),而我们有的一般是datas(src),所以适配器Adapter就是完成了数据源datas 转化成 ItemView的工作。

2,类的适配器模式

1)概念

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

2)类图(继承)

在这里插入图片描述

3)demo

充电器的例子。
在这里插入图片描述
i> Adaptee类,有220V电压:

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

ii> 我们需要的Target 接口:输出5V。

public interface Voltage5 {
    int output5V();
}

iii> 适配器类:将220V(Adaptee)转换为5V(Target )。

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;
    }
}

iv>使用

Voltage5 source = new ClassAdapter();
source.output5V();

4)优缺点

有局限性:

  1. Target 必须为接口才可以使用。(java是单一继承)
  2. 只能适配一个适配者

3,对象的适配器模式(推荐)

1)概念

持有Adaptee类的实例,以解决兼容性的问题。
即:持有 Adaptee类,实现 Target 类接口,完成 Adaptee->Target 的适配。

2)类图(组合)

在这里插入图片描述

3)demo

还是充电器例子:
在这里插入图片描述这种场景需要适配多个适配者对象,类适配器不能满足。此时用对象适配器来实现。

//适配者2
public class VoltageAmerican {

    public void outputAmerican(){
        System.out.println("美式插头转换成国标插头成功");
    }
}
/**
 * 对象的适配器模式 通过关联来实现 持有adaptee类的实例
 */
public class ObjectAdapter implements Voltage5 {

    public int output5V() {
        Voltage220 mVoltage220 = new Voltage220();
        VoltageAmerican voltageAmerican = new VoltageAmerican();

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

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

4)优缺点

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

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

1)概念

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

2)类图

在这里插入图片描述类似于模板方法,新的Adapter类中由两种方法组成:
抽象方法:由子类强制实现;
钩子方法:Adapter中定义为空方法,子类选择实现。

3)举例

①插板

我们有一个插板,上面有多个插座。多个插板放办公室,但我们只用来插主机,其他的插座不用不安全,我们不想要这些除三孔之外的插座。
在这里插入图片描述

/**
 * 电源插座接口
 */
public interface SocketInterface {
    public void HoleTwo();
    public void HoleThree();
    public void USB();

    /**
     * 美式插座
     */
    public void American();
}

给办公室放很多插板,每个插板都要实现4个方法,但我们只要一个三孔插座的方法,不想每次都多实现另外3个方法。


public class Socket implements SocketInterface {
    public void HoleTwo() {

    }

    public void HoleThree() {

    }

    public void USB() {

    }

    public void American() {

    }
}

然后我们定义一个接口适配器,把我们需要的方法设置为抽象方法,其他方法设置为空方法。

public abstract class InterfaceAdapter implements SocketInterface {
    public void HoleTwo() {

    }

    public abstract void HoleThree();

    public void USB() {

    }

    public void American() {

    }
}

新的插板诞生了:

public class SocketThree extends InterfaceAdapter{
    public void HoleThree() {

    }
}

②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) {
    }
}

对应的Adaptee:

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

        void onAnimationEnd(Animator animation);

        void onAnimationCancel(Animator animation);

        void onAnimationRepeat(Animator animation);
    }

②WindowListener适配器

java.awt.event下的接口WindowListener源码:

public interface WindowListener extends EventListener {
    public void windowOpened(WindowEvent e);
    public void windowClosing(WindowEvent e);
    public void windowClosed(WindowEvent e);
    public void windowIconified(WindowEvent e);
    public void windowDeiconified(WindowEvent e);
    public void windowActivated(WindowEvent e);
    public void windowDeactivated(WindowEvent e);
}

使用的时候需要实现每个方法:

WindowListener windowListener = new WindowListener(){

            @Override
            public void windowOpened(WindowEvent e) {

            }

            @Override
            public void windowClosing(WindowEvent e) {

            }

            @Override
            public void windowClosed(WindowEvent e) {

            }

            @Override
            public void windowIconified(WindowEvent e) {

            }

            @Override
            public void windowDeiconified(WindowEvent e) {

            }

            @Override
            public void windowActivated(WindowEvent e) {

            }

            @Override
            public void windowDeactivated(WindowEvent e) {

            }
        };

在某一种场景下我们只需要重写windowClosed方法,并且频繁实现这个接口,那么写一个Adapter类:
Adapter实现接口WindowListener,并将windowClosed方法设置为抽象类。


public abstract class WindowListenerAdapter implements WindowListener {
    @Override
    public void windowOpened(WindowEvent e) {

    }

    @Override
    public void windowClosing(WindowEvent e) {

    }

    public abstract void windowClosed(WindowEvent e);

    @Override
    public void windowIconified(WindowEvent e) {

    }

    @Override
    public void windowDeiconified(WindowEvent e) {

    }

    @Override
    public void windowActivated(WindowEvent e) {

    }

    @Override
    public void windowDeactivated(WindowEvent e) {

    }
}

其它地方需要实现的时候直接实现Adapter抽象类即可:

        WindowListenerAdapter windowListenerAdapter = new WindowListenerAdapter(){

            @Override
            public void windowClosed(WindowEvent e) {

            }
        };

5,三种适配器模式对比

1)实现

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

6,优缺点

1)优

① 将目标类和适配者类解耦;
② 增加了类的透明性和复用性;
③ 可以让任何两个没有关联的类一起运行,一个对象适配器可以把多个不同的适配者适配到同一个目标。

2)缺

  1. 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
  2. 对于类适配器,破坏了类的透明性,只能适配一个适配者类,而且目标类必须是抽象类;
  3. 对于对象适配器,修改起来比较复杂。

7,对比

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

①意图

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值