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

news2024/10/3 0:24:59

在这里插入图片描述

适配器设计模式

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

  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.coloradmin.cn/o/1471786.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

遭遇DDOS攻击忍气吞声?立刻报警!首都网警重拳出击,犯罪分子无所遁形

遭遇DDOS攻击忍气吞声?立刻报警!首都网警重拳出击 公元2024年2月24日18时许,笔者的个人网站突然遭遇不明身份者的DDOS攻击,且攻击流量已超过阿里云DDos基础防护的黑洞阈值,服务器的所有公网访问已被屏蔽,由…

观后感:UniAD

背景 首先定一个调,自动驾驶方向统一的大模型不是一般的公司就能做的,没几十张A100训练都训练死你,这批观后感旨在学习UniAD的思想,拓展一下眼界 UniAD将检测,跟踪,建图,轨迹预测这四个任务统一…

如何本地部署LightPicture结合cpolar内网穿透打造个人云图床

文章目录 1.前言2. Lightpicture网站搭建2.1. Lightpicture下载和安装2.2. Lightpicture网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 现在的手机越来越先进,功能也越来越多,而手机…

深度学习在过冷沸腾气泡动力学分割中的应用

Application of deep learning for segmentation of bubble dynamics in subcooled boiling 深度学习在过冷沸腾气泡动力学分割中的应用 期刊信息:International Journal of Multiphase Flow 2023 级别:EI检索 SCI升级版工程技术2区 SCI基础版工程技术3区…

Python之pyecharts的常见用法4-3D柱状图

目录 专栏导读背景1、3D柱状图代码 2、3D柱状图3、3D柱状图结尾 专栏导读 🌸 欢迎来到Python办可视化化专栏,目前专栏正在更新中 🏳️‍🌈 博客主页:请点击——> 一晌小贪欢的博客主页求关注 👍 此外…

300分钟吃透分布式缓存-15讲:如何深入理解、应用及扩展 Twemproxy?

Twemproxy 架构及应用 Twemproxy 是 Twitter 的一个开源架构,它是一个分片资源访问的代理组件。如下图所示,它可以封装资源池的分布及 hash 规则,解决后端部分节点异常后的探测和重连问题,让 client 访问尽可能简单,同…

LeetCode 1038.从二叉搜索树到更大和树

给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。 提醒一下, 二叉搜索树 满足下列约束条件: 节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左…

c++:vector的相关oj题(136. 只出现一次的数字、118. 杨辉三角、26. 删除有序数组中的重复项、JZ39 数组中出现次数超过一半的数字)

文章目录 1. 136. 只出现一次的数字题目详情代码(直接来异或)思路 2. 118. 杨辉三角题目详情代码1思路代码2思路2 3. 26. 删除有序数组中的重复项题目详情代码思路 4. JZ39 数组中出现次数超过一半的数字题目详情代码1(暴力)思路1代码2&#…

《论文阅读》利用提取的情感原因提高共情对话生成的内容相关性 CCL 2022

《论文阅读》利用提取的情感原因提高共情对话生成的内容相关性 前言简介模型架构情绪识别情绪原因提取实验结果示例总结前言 亲身阅读感受分享,细节画图解释,再也不用担心看不懂论文啦~ 无抄袭,无复制,纯手工敲击键盘~ 今天为大家带来的是《Using Extracted Emotion Caus…

el-tab-pane标签页如何加图标

效果如下 主要修改 <el-tab-pane name"tab6" v-if"subOrderType 10 && urlname ! wgSalesTerminationOrder"><span slot"label"> 售后判责<span class"el-icon-warning" style"color:#F66B6C;"&…

电脑dll缺失怎么办,找不到dll的多种解决方法分享

dll文件在计算机领域中扮演着至关重要的角色&#xff0c;它代表的是Dynamic Link Library&#xff08;动态链接库&#xff09;文件。那么&#xff0c;究竟什么是dll文件呢&#xff1f;简单来说&#xff0c;dll文件是一种特殊的程序模块&#xff0c;其中包含了可以被多个应用程序…

Web3的奇迹:数字世界的新篇章

在数字化时代的潮流中&#xff0c;Web3正以其令人振奋的潜力和前景引领着我们进入一个全新的数字时代。作为互联网的下一代&#xff0c;Web3将重新定义我们对数字世界的认知和体验&#xff0c;为我们带来无限的可能性和奇迹。本文将深入探讨Web3的重要性、核心特征以及未来展望…

Nginx----高性能的WEB服务端(二)

一、高级配置 1、网页的状态页 基于nginx 模块 ngx_http_stub_status_module 实现&#xff0c;在编译安装nginx的时候需要添加编译参数 --with-http_stub_status_module&#xff0c;否则配置完成之后监测会是提示语法错误注意: 状态页显示的是整个服务器的状态,而非虚拟主机的…

【力扣白嫖日记】180.连续出现的数字

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 180.连续出现的数字 表&#xff1a;Logs 列名类型idintnumvarchar 找出所有至少连续出现三次的数字。 返回…

Spring之AOP源码解析(下)

前言 在上一遍文章中,我们主要讲解了ProxyFactory在Spring完成AOP动态代理的过程中发挥的作用。这一篇我们主要讲解这些注解都是如何注入Advisors,然后分析这些Advisors生效的条件 注解都是如何注入Advisor并匹配的 EnableTransactionManagement注解 我们在之前提到EnableT…

vue2实现无感刷新token

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 引言&#xff1a; &#x1f4…

商家入驻平台怎么让资金自动分配给商家

最近很多上线了多商户电商系统的朋友咨询&#xff0c;我们平台的用户支付后&#xff0c;钱进入了我们的对公账户&#xff0c;怎样让钱在走完流程后&#xff0c;自动进入商家的账户呢&#xff1f;今天商淘云为您分享商户入驻平台自动分配给商家资金的三种方法。 首先是平台应建立…

用户体验设计师如何在 2024抢占先机?

01. 严峻的经济形势和就业市场 我们生活在一个通货膨胀的时代。就从超市抓几个苹果、卷心菜、鸡蛋&#xff0c;看看价格吧&#xff01;我不得不多次检查收据&#xff0c;因为我简直不敢相信。外出就餐费用上涨了 10-20%&#xff0c;现在 Spotify 和 YouTube 要求收取更高的订阅…

Android 水波纹扩散效果实现

人生只是一种体验&#xff0c;不必用来演绎完美。 效果图 View源码 package com.android.circlescalebar.view;import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.…

2024.2.27 模拟实现 RabbitMQ —— 网络通信设计(客户端)

目录 需求分析 RabbitMQ 客户端设定 ConnectionFactory&#xff08;连接工厂&#xff09; Connection&#xff08;连接&#xff09; Channel&#xff08;通道&#xff09; 针对 客户端 和 服务器 单元测试 需求分析 RabbitMQ 客户端设定 一个客户端可以有多个模块每个模块…