【深入理解设计模式】适配器设计模式

在这里插入图片描述

适配器设计模式

适配器设计模式是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口,从而使得原本由于接口不兼容而不能一起工作的类能够一起工作。适配器模式通常用于以下场景:

  1. 现有接口与需求不匹配:当需要使用的类的接口与当前系统的接口不匹配时,可以创建一个适配器来进行转换。

  2. 类的功能需要增强:有时候,为了增强现有类的功能而不修改原有代码,可以使用适配器模式。

概述

如果去欧洲国家去旅游的话,他们的插座如下图最左边,是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑,手机在当地不能直接充电。所以就需要一个插座转换器,转换器第1面插入当地的插座,第2面供我们充电,这样使得我们的插头在当地能使用。生活中这样的例子很多,手机充电器(将220v转换为5v的电压),读卡器等,其实就是使用到了适配器模式。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

定义:

​ 将一个类的接口转换成客户端希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。

​ 适配器模式分为类适配器模式对象适配器模式,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

结构

适配器模式(Adapter)包含以下主要角色:

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 被适配者(Adaptee):需要被适配的类。它定义了适配器所需的原始接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

适配器模式的实现可以分为两种方式:

  • 类适配器模式:通过继承被适配类和实现目标接口来实现适配器。这种方式需要多重继承或接口实现,不过在一些编程语言中并不支持多重继承,因此并不常用。

  • 对象适配器模式:通过在适配器类中组合或聚合被适配类的实例来实现适配器。这种方式更加灵活,因为它可以适配多个类而不仅限于单一类。

适配器设计模式能够很好地解决不同接口之间的兼容性问题,使得原本不兼容的类能够协同工作,提高了代码的复用性和灵活性。

类适配器模式

实现方式:定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。

【例】读卡器

现有一台电脑只能读取SD卡,而要读取TF卡中的内容的话就需要使用到适配器模式。创建一个读卡器,将TF卡中的内容读取出来。

代码如下:

/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 电脑类
 */
public class Computer {

    // 向SD卡中写数据(目标接口只能是SDCard)
    public void writeSD(SDCard sdCard, String msg) {
        sdCard.writeMsg(msg);
    }

    // 从SD卡中读取数据(目标接口只能是SDCard)
    public String readSD(SDCard sdCard) {
        return sdCard.readMsg();
    }
}
/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 目标接口 - SD卡接口
 */
public interface SDCard {

    // 向SD卡中写数据
    void writeMsg(String msg);

    // 从SD卡中读数据
    String readMsg();

}
/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 目标接口实现类 - SDCard实现类
 */
public class SDCardImpl implements SDCard{
    @Override
    public void writeMsg(String msg) {
        System.out.println("write msg to sd card"+msg);
    }

    @Override
    public String readMsg() {
        return "read msg from sd card";
    }
}
/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 适配者 - TFCard
 */
public interface TFCard {

    // 向TF卡中写数据
    void writeMsg(String msg);

    // 从TF卡中读数据
    String readMsg();

}
/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 具体适配者 - TFCard具体实现类
 */
public class TFCardImpl implements TFCard{
    @Override
    public void writeMsg(String msg) {
        System.out.println("write msg to tf card"+msg);
    }

    @Override
    public String readMsg() {
        return "read msg from tf card";
    }
}

/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 适配器类 继承被适配者类 实现目标接口
 */
public class SDAdapterTF extends TFCardImpl implements SDCard{

    @Override
    public void writeMsg(String msg) {
        super.writeMsg(msg);
    }

    @Override
    public String readMsg() {
        return super.readMsg();
    }
}
/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 客户端 - 测试类
 */
public class Client {

    public static void main(String[] args) {
        Computer computer = new Computer();

        SDCard sdCard = new SDCardImpl();
        String s = computer.readSD(sdCard);
        System.out.println(s);

        System.out.println("=============");
		// 通过适配器,将TF卡转换为实现SD接口的适配器
        SDAdapterTF adapterTF = new SDAdapterTF();
        // 读取适配器中的数据
        String s1 = computer.readSD(adapterTF);
        System.out.println(s1);

    }
}

类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之不可用。

对象适配器模式

实现方式:对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。

【例】读卡器

我们使用对象适配器模式将读卡器的案例进行改写。

类适配器模式的代码,我们只需要修改适配器类(SDAdapterTF)和测试类。

/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 适配器类 继承适配者类 实现目标接口
 */
public class SDAdapterTF implements SDCard {

    private TFCard tfCard;

    public SDAdapterTF(TFCard tfCard) {
        this.tfCard = tfCard;
    }

    @Override
    public void writeMsg(String msg) {
        tfCard.writeMsg(msg);
    }

    @Override
    public String readMsg() {
        return tfCard.readMsg();
    }
}

/**
 * @author OldGj 2024/02/23
 * @version v1.0
 * @apiNote 客户端 - 测试类
 */
public class Client {

    public static void main(String[] args) {
        Computer computer = new Computer();

        SDCard sdCard = new SDCardImpl();
        String s = computer.readSD(sdCard);
        System.out.println(s);

        System.out.println("=============");
        // 将TF卡传入适配器中
        SDAdapterTF sdAdapterTF = new SDAdapterTF(new TFCardImpl());
        String s1 = computer.readSD(sdAdapterTF);
        System.out.println(s1);
    }
}

注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter ,实现所有方法。而此时我们只需要继承该抽象类即可。

应用场景

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

JDK中的适配器模式:

当涉及字符流(Reader)和字节流(InputStream)之间的适配时,通常会使用适配器模式。这种适配器模式的目的是让字符流和字节流能够协同工作,尽管它们的接口不同。

  1. Reader(字符流)Reader 是 Java 中用于读取字符流的抽象基类。它定义了读取字符数据的一系列方法,如 read()close() 等。字符流是以字符为单位进行读取和写入的,对文本数据的处理更为方便。

  2. InputStream(字节流)InputStream 是 Java 中用于读取字节流的抽象基类。它定义了读取字节数据的一系列方法,如 read()close() 等。字节流是以字节为单位进行读取和写入的,适用于处理二进制数据。

  3. InputStreamReader(适配器)InputStreamReader 是 Java 中用于将字节流转换为字符流的适配器类。它实现了 Reader 接口,并包装了一个 InputStream 对象。InputStreamReader 通过在字节流和字符流之间进行转换,使得字符流能够读取字节流中的数据。它的作用就是将字节流适配成字符流,使得原本不兼容的字符流和字节流能够一起工作。

在使用 InputStreamReader 时,它会接受一个 InputStream 对象作为参数,并将该对象转换为字符流,因此它充当了字符流和字节流之间的适配器。这样一来,当我们需要使用字符流操作时,可以直接使用 Reader 接口及其实现类,而不必直接操作字节流。InputStreamReader 负责将底层的字节流适配成字符流,从而实现了字符流和字节流之间的适配。

总而言之,ReaderInputStream 之间的适配器模式的典型应用就是通过 InputStreamReader 将字节流适配成字符流,使得字符流和字节流能够协同工作,这是适配器模式在 Java IO 中的一个典型应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/410454.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IP对讲终端SV-6002(防水)

SV-6002(防水)是一款IP对讲终端,具有10/100M以太网接口,其接收网络的音频数据,解码后播放,外部DC12~24V电源供电端子,提供单路2W的音频输出。基于TCP/IP网络通信协议和数字音频技术,…

【Java EE初阶二十三】servlet的简单理解

1. 初识servlet Servlet 是一个比较古老的编写网站的方式,早起Java 编写网站,主要使用 Servlet 的方式,后来 Java 中产生了一个Spring(一套框架),Spring 又是针对 Servlet 进行了进一步封装,从而让我们编写网站变的更简单了;Sprin…

都有金蝶了,也能开发报表,为什么要用BI?

很多企业在一开始时都会有这样的困惑:我都有金蝶ERP了,也能自己开发报表,为什么还要买BI? 答案是显而易见的,金蝶ERP毕竟不是专业的数据分析系统,它的主要任务是在企业管理流程上,虽然很多企业…

Linux内核网络

文章目录 前言网络协议栈图解功能 发送Linux内核网络数据包图解流程 接收Linux内核网络数据包图解流程 最后 前言 你好,我是醉墨居士,因为Linux内核涉及的内容极多,我们初学者如果一上来就开始深挖细节,很有可能会在Linux内核代码…

MySQL - 事务日志

目录 1. redo日志 1.1 为什么需要REDO日志 1.2 REDO日志的好处、特点 1. 好处 2. 特点 1.3 redo的组成 1.4 redo的整体流程 1.5 redo log的刷盘策略 1.6 不同刷盘策略演示 1. 流程图 ​编辑2. 举例 1.7 写入redo log buffer 过程 1.8 redo log file 1. 相关参数…

[云原生] 二进制安装K8S(中)部署网络插件和DNS

书接上文,我们继续部署剩余的插件 一、K8s的CNI网络插件模式 2.1 k8s的三种网络模式 K8S 中 Pod 网络通信: (1)Pod 内容器与容器之间的通信 在同一个 Pod 内的容器(Pod 内的容器是不会跨宿主机的)共享…

批量解决opencv cv2.imread读取32位抠图png图像后,出现隐藏背景无法去除的问题

一、问题展示 1.原始png含蒙版抠图信息:位深度为32位,4通道图像信息,含蒙版背景信息 2.使用opencv读取保存后图像信息:位深度为24位,3通道图像信息,显示了扣除的背景 二、问题分析 1.用cv模块无法识别深度…

Stable Diffusion 绘画入门教程(webui)-ControlNet(线稿约束)

上篇文章介绍了openpose,本篇文章介绍下线稿约束,关于线稿约束有好几个处理器都属于此类型,但是有一些区别。 包含: 1、Canny(硬边缘):识别线条比较多比较细,一般用于更大程度得还原照片 2、ML…

C++ : string类

目录 介绍: string类的七种构造函数: string类的第三个构造函数 string类的第四个构造函数 string类的第五个构造函数 string类的第六个构造函数 string类常用的构造 string类对象的访问遍历操作 第一种遍历方式: 第二种遍历方…

使用Node.js开发RESTful API

在当今信息时代,不管是企业级应用还是个人项目,都离不开RESTful API的使用。RESTful API 是现代 web 应用的基石,通过它,我们可以实现前后端的高效沟通和数据传输。而在开发 RESTful API 的过程中,Node.js 的强大功能和…

AR应用的开发流程

增强现实(Augmented Reality,AR)是一种技术,它将虚拟信息叠加在真实世界中,通过计算机生成的视觉、听觉、触觉等感官反馈,将虚拟元素与现实世界进行交互。这种技术使得用户可以与现实世界中的虚拟对象进行互…

vue插件——vue-print-nb 实现打印功能

之前写过好多关于打印的功能,通过windowprint组合键来实现打印。 今天遇到一个需求,就是使用vue插件来实现打印功能。 最终效果图如下: 下面介绍解决步骤: 解决步骤1:安装vue-print-nb插件——npm install vue-p…

flutter开发实战-手势Gesture与ListView滚动竞技场的可滑动关闭组件

flutter开发实战-手势Gesture与ListView滚动竞技场的可滑动关闭组件 最近看到了一个插件,实现一个可滑动关闭组件。滑动关闭组件即手指向下滑动,组件随手指移动,当移动一定位置时候,手指抬起后组件滑出屏幕。 一、GestureDetect…

配置多个后端 API 代理

在开发 React 应用时,通常会涉及到与后端 API 的交互。而在开发过程中,我们经常需要在开发环境中使用代理来解决跨域请求的问题。Create React App 提供了一种简单的方式来配置代理,即通过创建一个名为 setupProxy.js 的文件来配置代理规则。…

力扣链表篇

以下刷题思路来自代码随想录以及官方题解 文章目录 203.移除链表元素707.设计链表206.反转链表24.两两交换链表中的节点19.删除链表的倒数第N个节点面试题 02.07. 链表相交142.环形链表II 203.移除链表元素 给你一个链表的头节点 head 和一个整数 val ,请你删除链…

一个具有强大PDF处理能力的.Net开源项目

PDF具有跨平台、可读性强、不可修改性、无需特定阅读软件、内容安全等好处,在工作中经常都会用到。 所以,我们在项目开发中,经常需要生成PDF的文件,或者把Html、Xml等文件转化为PDF格式。 今天给大家推荐一个具有PDF处理能力的.…

计算机设计大赛 深度学习大数据物流平台 python

文章目录 0 前言1 课题背景2 物流大数据平台的架构与设计3 智能车货匹配推荐算法的实现**1\. 问题陈述****2\. 算法模型**3\. 模型构建总览 **4 司机标签体系的搭建及算法****1\. 冷启动**2\. LSTM多标签模型算法 5 货运价格预测6 总结7 部分核心代码8 最后 0 前言 &#x1f5…

vue - - - - Vue3+i18n多语言动态国际化设置

Vue3i18n多语言动态国际化设置 前言一、 i18n 介绍二、插件安装三、i18n配置3.1 创建i18n对应文件夹/文件3.2 en-US.js3.3 zh-CN.js3.4 index.js 四、 mian.js 引入 i18n配置文件五、 组件内使用六、使用效果 前言 继续【如何给自己的网站添加中英文切换】一文之后&#xff0c…

Folx Pro Mac中文p破解版如何使用?为您带来Folx Pro 详细使用教程!

​ Folx pro 5 中文版是mac上一款功能强大的老牌加速下载软件,新版本的Folx pro整体界面非常的简洁和漂亮,具有非常好用的分类管理功能,支持高速下载、定时下载、速度控制、iTunes集成等功能。Folx pro兼容主流的浏览器,不但可以下…

AI对话系统app开源

支持对接gpt,阿里云,腾讯云 具体看截图 后端环境:PHP7.4MySQL5.6 软件:uniapp 废话不多说直接上抗揍云链接: https://mny.lanzout.com/iKFRY1o1zusf 部署教程请看源码内的【使用教程】文档 欢迎各位转载该帖/源码
最新文章