设计模式(七)适配器模式

栏目: 后端 · 发布时间: 5年前

内容简介:适配器模式是将一个类的接口转换成客户希望的另外一个接口,身边很多东西都是适用于适配器模式的,笔记本的电源(也叫电源适配器),是将220V的交流电转换为笔记本电脑所需要的12V(电流先忽略),笔记本电脑的各种接口,VGA转Hdml,USB-TypeA 转 USB-TypeC,亦或者你在香港买了个手机,充电器是你生活中没见过的三孔插座通过一个转换头转换为国内常用的插头,很多例子都能很形象的解释这个设计模式。适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而

适配器模式是将一个类的接口转换成客户希望的另外一个接口,身边很多东西都是适用于适配器模式的,笔记本的电源(也叫电源适配器),是将220V的交流电转换为笔记本电脑所需要的12V(电流先忽略),笔记本电脑的各种接口,VGA转Hdml,USB-TypeA 转 USB-TypeC,亦或者你在香港买了个手机,充电器是你生活中没见过的三孔插座通过一个转换头转换为国内常用的插头,很多例子都能很形象的解释这个设计模式。适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的。一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起,做法是将类自己的接口包裹在一个已存在的类中。

UML角色

Source:需要被适配的类、接口、对象,即Datas。

Destination:需要得到的类,Source通过适配得到的类对象,也就是我们期待得到的借口。

Adapter:适配器类,协调Source和Destination,使两者能够协同工作。

适用场景

1,系统需要使用现有的类,但现有的类却不兼容。

2,需要建立一个可以重复使用的类,用于一些彼此关系不大的类,并易于扩展,以便于面对将来会出现的类。

3,需要一个统一的输出接口,但是输入类型却不可预知。

Demo

简单的抽象一个场景:手机充电需要将220V的交流电转化为手机锂电池需要的5V直流电,我们的demo就是写一个电源适配器,将 AC220v ——> DC5V,其实适配器模式可以简单的分为三类:类适配器模式、对象的适配器模式、接口的适配器模式。我们就以这三种模式来实现上述步骤。

类适配器模式

就上面提到的功能,简单的使用类适配器模式,Source类如下:

package com.demo.adapter.classadapter;

/**
 * Created by italkbb on 2018/1/24.
 */

public class AC220 {
    public int output220V(){
        int output = 220;
        return output;
    }
}

复制代码

我们的目标类Destination,只需要定义方法,由适配器来转化:

package com.demo.adapter.classadapter;

/**
 * Created by italkbb on 2018/1/24.
 */

public interface DC5 {
    int output5V();
}
复制代码

Adapter类如下:

package com.demo.adapter.classadapter;

/**
 * Created by italkbb on 2018/1/24.
 */

public class PowerAdapter extends AC220 implements DC5 {
    @Override
    public int output5V() {
        int output = output220V();
        return (output / 44);
    }
}

复制代码

对于使用,也很简单:

/**
     * 类适配器使用demo
     */
    private void initClassAdapter() {
        DC5 dc5 = new com.demo.adapter.classadapter.PowerAdapter();
        dc5.output5V();
    }

复制代码

因为 java 单继承的缘故,Destination类必须是接口,以便于Adapter去继承Source并实现Destination,完成适配的功能,但这样就导致了Adapter里暴露了Source类的方法,使用起来的成本就增加了。

对象适配器模式

对于同样的逻辑,我们在以对象适配器模式实现。我们保留AC220和DC5两个基本类,我们让Adapter持有Destination类的实例,然后再实现DC5,以这种持有对象的方式来实现适配器功能:

package com.demo.adapter.objadapter;

import com.demo.adapter.classadapter.AC220;
import com.demo.adapter.classadapter.DC5;

/**
 * Created by italkbb on 2018/1/24.
 */

public class PowerAdapter implements DC5{
    private AC220 mAC220;

    public PowerAdapter(AC220 ac220){
        this.mAC220 = ac220;
    }

    @Override
    public int output5V() {
        int output = 0;
        if (mAC220 != null) {
            output = mAC220.output220V() / 44;
        }
        return output;
    }
}

复制代码

使用代码:

/**
     * 对象适配器模式demo
     */
    private void initObjAdapter() {
        com.demo.adapter.objadapter.PowerAdapter adapter = new com.demo.adapter.objadapter.PowerAdapter(new AC220());
        adapter.output5V();
    }

复制代码

对象适配器和类适配器其实算是同一种思想,只不过实现方式不同。再回想装饰者模式,装饰者是对Source的装饰,使用者毫无察觉到Source被装饰,也就是用法不变。而对于适配器模式用法还是有改变的。

接口适配器模式

对于接口适配器模式,我们就不用担着眼于220->5,我们的接口可以有更多的抽象方法,这一点在android开发中有很多影子,动画的适配器有很多接口,但我们只需要关心我们需要的回调方法(详见AnimatorListenerAdapter类),我们把接口比作万能适配器:

package com.demo.adapter.interfaceadapter;

/**
 * Created by italkbb on 2018/1/24.
 */

public interface DCOutput {
    int output5V();
    int output9V();
    int output12V();
    int output24V();
}

复制代码

然后我们要用的是5V的电压,所以关心5V的适配:

package com.demo.adapter.interfaceadapter;

import com.demo.adapter.classadapter.AC220;

/**
 * Created by italkbb on 2018/1/24.
 */

public class Power5VAdapter extends PowerAdapter {

    public Power5VAdapter(AC220 ac220) {
        super(ac220);
    }

    @Override
    public int output5V() {
        int output = 0;
        if (mAC220 != null) {
            output = mAC220.output220V() / 44;
        }
        return output;
    }
}

复制代码

但是我们必须存在一个中间适配器,用于实现默认的接口方法,以至于减少我们适配器的代码量,让代码更加清晰:

package com.demo.adapter.interfaceadapter;

import com.demo.adapter.classadapter.AC220;

/**
 * Created by italkbb on 2018/1/24.
 * 这里抽象类其实就写了空方法,等着子类去实现需要的方法。
 */
public abstract class PowerAdapter implements DCOutput{
    protected AC220 mAC220;

    public PowerAdapter(AC220 ac220){
        this.mAC220 = ac220;
    }

    @Override
    public int output5V() {
        return mAC220.output220V();
    }

    @Override
    public int output9V() {
        return mAC220.output220V();
    }

    @Override
    public int output12V() {
        return mAC220.output220V();
    }

    @Override
    public int output24V() {
        return mAC220.output220V();
    }
}

复制代码

这样一来我们就只需要重写父类我们关心的方法了,当然我们有时候可以省略Power5VAdapter类,因为内部类可以实现我们的方法,就跟使用setOnClickOnLintener(new OnClickOnLintener(){…})一样,我们来看使用:

/**
     * 接口适配器模式demo
     */
    private void initinterfaceAdapter() {
        // 已经实现了子类
        com.demo.adapter.interfaceadapter.Power5VAdapter power5VAdapter = new Power5VAdapter(new AC220());
        power5VAdapter.output5V();

        // 直接实现子类
        com.demo.adapter.interfaceadapter.PowerAdapter powerAdapter = new PowerAdapter(new AC220()) {
            @Override
            public int output5V() {
                int output = 0;
                if (mAC220 != null) {
                    output = mAC220.output220V() / 44;
                }
                return output;
            }
        };
        powerAdapter.output5V();
    }
复制代码

这样也实现了这个适配功能,而且可以说易于扩展。

总结

可以说Source的存在形式决定了适配器的名字,类适配器就是继承Source类,对象适配器就是持有Source类,接口适配器就是实现Source接口。

note:我以为努力就会有回报的


以上所述就是小编给大家介绍的《设计模式(七)适配器模式》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

LaTeX入门

LaTeX入门

刘海洋 / 电子工业出版社 / 2013-6-1 / CNY 79.00

LaTeX 已经成为国际上数学、物理、计算机等科技领域专业排版的实际标准,其他领域(化学、生物、工程、语言学等)也有大量用户。本书内容取材广泛,涵盖了正文组织、自动化工具、数学公式、图表制作、幻灯片演示、错误处理等方面。考虑到LaTeX 也是不断进化的,本书从数以千计的LaTeX 工具宏包中进行甄选,选择较新而且实用的版本来讲解排版技巧。 为了方便读者的学习,本书给出了大量的实例和一定量的习......一起来看看 《LaTeX入门》 这本书的介绍吧!

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具