IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Javc设计模式——适配器模式 -> 正文阅读

[Java知识库]Javc设计模式——适配器模式

一、概述

首先需要介绍一下适配器模式是干什么的

将一个类的接口转换成客户希望的另外一个接口。


简单的说,适配器模式就是为了使得我们可以通过一定的处理来使用原本不兼容的类进行交互,而这个处理的过程或者说进行处理的类就是我们所说的适配器,适配器的两端就是被适配者与要适配者
比较常见的例子就是我们的插座与充电器了,通常我们的插座电压都是额定电压220V,但是我们要给手机充电的话肯定不可能直接220V的,这时候我们就需要一个插头来将插座的220V转换成适合我们手机的电压,在这里面手机就要我们的被适配者,而插座就是要适配者,手机充电插头就充当着适配者的角色。

适配器模式也是很很多种的,类适配器、对象适配器、双向适配器……,各个模式的介绍和之间的差异就先不介绍了,放在总结里。

二、角色与职责

Target:

  • 定义Client使用的与特定领域相关的接口
  • 要被人适配他(被适配者)

Client

  • 与符合Target接口的对象协同
  • 调用被适配者

Adaptee

  • 定义一个已经存在的接口,这个接口需要适配
  • 需要适配别人(要适配者)

Adapter

  • 对Adaptee的接口与Target接口进行适配

我们使用插座与手机充电器的的例子,那么我们220V额定电压的插座就是Adaptee,而我们的手机充电插口就是Target,要将220V的电压变成适合给手机充电的电压,那么充电器在这个环节中就是作为一个适配器(Adapter)来存在的。

三、类适配器

首先我们来看类适配器,UML图如下
类适配器

由上图可以看到,类适配器模式是通过让Adapter(适配器)实现Target(被适配者)的抽象接口,然后继承Adaptee(要适配者),具体适配过程是由我们的适配器的Resuest()方法中对Adaptee(要适配者)的SpecificRequest()方法进行适配,使得适配器的Request()方法返回我们需要的被适配者,供我们使用。

下面通过代码来实现一下类适配器模式,我们还是使用插座和充电器的例子
首先创建一个模仿插座的类,其中的方法返回一个220V的电压值

/**
 * @author ZhongJing </p>
 * @Description 插座(被适配的类) </p>
 */
public class Voltage220V {

    public int output220V() {
        int src = 220;
        System.out.println("电压=" + src + "伏");
        return src;
    }

}

然后我们定义一个类来模拟手机需要的额定电压

/**
 * @author ZhongJing </p>
 * @Description 手机额定电压(适配接口) </p>
 */
public interface IVoltage5V {

    public int output5V();

}

有了被AdapteeTarget之后,我们需要一个适配器Adapter来将220V的电压转为手机支持的充电电压

/**
 * @author ZhongJing </p>
 * @Description 适配器 </p>
 */
public class VoltageAdapter extends Voltage220V implements IVoltage5V {

    @Override
    public int output5V() {
        // 获取到220V的电压
        int srcV = output220V();
        // 处理电压,转成5V
        int dstV = srcV / 44;
        return dstV;
    }
}

创建一个手机类,其中一个方法为模拟手机充电,方法需要一个额定电压Target的参数

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Phone {

    public void charging(IVoltage5V voltage) {
        if (voltage.output5V() == 5) {
            System.out.println("电压为5V,可以充电~");
        } else if (voltage.output5V() > 5) {
            System.out.println("电压大于5V,不能充电~");
        }
    }

}

下面我们写一个main方法来跑一下我们编写的代码,验证是否正确

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Client {

    public static void main(String[] args) {

        System.out.println("类适配器模式");

        Phone phone = new Phone();
        phone.charging(new VoltageAdapter());

    }

}

运行结果如下:

类适配器模式
电压=220伏
电压为5V,可以充电~

四、对象适配器

对象适配器的UML图如下:

对象适配器

可以看到对象适配器并没有去继承Adaptee,而是通过关联(成员属性)的方式来使用Adaptee
和类适配器唯一的区别就是适配器的写法,具体代码如下:

/**
 * @author ZhongJing </p>
 * @Description 适配器 </p>
 */
public class VoltageAdapter implements IVoltage5V {

    private Voltage220V voltage220V;

    public VoltageAdapter() {
    }

    public VoltageAdapter(Voltage220V voltage220V) {
        this.voltage220V = voltage220V;
    }

    @Override
    public int output5V() {
        int dst = 0;
        if (voltage220V != null) {
            int src = voltage220V.output220V();
            System.out.println("使用对象适配器进行适配");
            dst = src / 44;
            System.out.println("适配完成,输出电压为:" + dst);
        }
        return dst;
    }
}

别的代码和类适配器都是一样的,就不多做赘述了,我们写一段测试代码来测试一下

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Client {

    public static void main(String[] args) {

        System.out.println("对象适配器模式");

        Phone phone = new Phone();
        phone.charging(new VoltageAdapter(new Voltage220V()));

    }

}

运行结果如下:

对象适配器模式
电压=220伏
使用对象适配器进行适配
适配完成,输出电压为:5
电压为5V,可以充电~

对象适配器模式相比于类适配器模式会更加灵活一些,通过我们的测试代码可以发现,我们的Adaptee是通过构造器传入的,这样可以更方便我们代码的扩展(多态),而且类适配器如果Target不是一个接口,也是一个类的话,Java中是不支持多继承的,这是一个很严重的问题。

五、双向适配器

双向适配器其实算是对象适配器的一个变种
就是当适配器中同时拥有TargetAdaptee的引用时候,适配器定义针对二者的方法,既可以将Target适配为Adaptee,也可以将Adaptee适配为Target,不再区分谁是适配者谁是被适配者,二者皆可。
UML图如下所示:

双向适配器

代码大致如下

/**
 * @author ZhongJing </p>
 * @Description </p>
 */
public class Adapter implements Target, Adaptee {

    private Target target;

    private Adaptee adaptee;

    public Adapter(Target target) {
        this.target = target;
    }

    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    public void setTarget(Target target) {
        this.target = target;
    }

    public void setAdaptee(Adaptee adaptee) {
        this.adaptee = adaptee;
    }

    @Override
    public void specificRequest() {
        // 适配代码……
        target.request();
    }

    @Override
    public void request() {
        // 适配代码……
        adaptee.specificRequest();
    }
}

六、总结

本篇共介绍了3种适配器模式,分别为类适配器、对象适配器以及双向适配器

总的来说适配器模式的优点如下:

  • 将目标类和适配者类解耦,通过一个中间的适配器来复用原有的类而不需要去改变原有代码
  • 具有较高的灵活性和可扩展性

其中对象适配器和类适配器也各有各的优点以及缺点

类适配器优点就在于适配器类是继承了Adaptee,那么我们就可以在适配器类中对Adaptee的一些方法进行自定的修改与重写,灵活性更强
缺点也就是因为类适配器需要继承Adaptee,当我们的Target是一个类而不是接口的时候,类适配器就不适用于我们了。

对象适配器的优点在于其通过关联的关系将Adaptee作为一个成员属性包含在内,那么我们就可以运行多态将Adaptee以及他的子类都适配到Target,当然,这是在Adaptee和他的子类遵循“里氏替换原则”的前提下。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-26 22:00:25  更:2021-12-26 22:01:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:36:28-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码