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

在这里插入图片描述

适配器设计模式

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

  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{@Overridepublic void writeMsg(String msg) {System.out.println("write msg to sd card"+msg);}@Overridepublic 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{@Overridepublic void writeMsg(String msg) {System.out.println("write msg to tf card"+msg);}@Overridepublic String readMsg() {return "read msg from tf card";}
}

/*** @author OldGj 2024/02/23* @version v1.0* @apiNote 适配器类 继承被适配者类 实现目标接口*/
public class SDAdapterTF extends TFCardImpl implements SDCard{@Overridepublic void writeMsg(String msg) {super.writeMsg(msg);}@Overridepublic 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;}@Overridepublic void writeMsg(String msg) {tfCard.writeMsg(msg);}@Overridepublic 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.rhkb.cn/news/264640.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【力扣 - 买卖股票的最佳时机】

题目描述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的…

【Linux深入剖析】进程优先级 | 命令行参数 | 环境变量

📙 作者简介 :RO-BERRY 📗 学习方向:致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 📒 日后方向 : 偏向于CPP开发以及大数据方向,欢迎各位关注,谢谢各位的支持 目录 1.进程优先级2.Linux…

【MySQL面试复习】详细说下事务的特性

系列文章目录 在MySQL中,如何定位慢查询? 发现了某个SQL语句执行很慢,如何进行分析? 了解过索引吗?(索引的底层原理)/B 树和B树的区别是什么? 什么是聚簇索引(聚集索引)和非聚簇索引…

Unity(第六部)向量的理解和算法

标量:只有大小的量。185 888 999 (类似坐标) 向量:既有大小,也有方向。(类似以个体为主体的方向,前方一百米) 向量的模:向量的大小。(类似以个体为主体的方向,前方一百米、只取一百米…

Leetcoder Day23| 回溯part03:组合+分割

语言:Java/Go 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的所有不同组合 ,并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…

状态机-----

1.原理 同步的意思就是状态的跳转都是在时钟的作用下跳转的,有限是指状态机中状态的个数是有限的。两种状态机的共同点都是状态的跳转只和输入有关,区别就是如果最后的输出只和当前状态有关而与输入无关,则是moore型状态机。如果最后的输出不…

Go 如何按行读取(大)文件?尝试 bufio 包提供的几种方式

嗨,大家好!我是波罗学。本文是系列文章 Go 技巧第十七篇,系列文章查看:Go 语言技巧。 本文将介绍 Go 如何按行读取文件,基于此会逐步延伸到如何按块读取文件。 引言 我们将要介绍的按行读取文件的方式其实是非常适合…

Laravel04 eloquent

eloquent 1. eloquent2. 创建eloquent model 以及 取数据 1. eloquent 文档地址: https://learnku.com/docs/laravel/8.x/eloquent/9406 下面是我们,通过laravel的DB类从数据库中获取了post记录,那么有没有可能我们直接获取一个post对象&am…

pycharm控制STM32F103ZET6拍照并上位机接收显示(OV7670、照相机、STM32、TFTLCD)

基于STM32的照相机 准备工作最终效果一、下位机1、主函数2、OV7670初始化 二、上位机1、控制拍照2、接收图片数据 三、资源获取 准备工作 一、硬件及片上资源: 1,串口1(波特率:921600,PA9/PA10通过usb转ttl连接电脑,或者其他方法)上传图片数据至上位机 2,串口2(波特…

一文读懂:AWS 网络对等互连(VPC peering)实用操作指南

VPC peering connection-网络对等互连在您的 Atlas VPC 和云提供商的 VPC 之间建立私有连接。该连接将流量与公共网络隔离以提高安全性。本篇文章有VPC peering的操作指南以及价格等信息。如还有疑问请联系我们MongoDB的销售,客户成功经理或解决方案架构师。 1 使用…

【C之·预处理器】

系列文章目录 文章目录 前言一、预处理指令1. #line的用法1.1 概述 2. #error2.1 概述 二、预定义宏三、示例1. #line2. #error3. 预定义宏 总结 前言 C 预处理器不是编译器的组成部分,但是它是编译过程中一个单独的步骤。简言之,C 预处理器只不过是一个…

C++面试宝典第32题:零钱兑换

题目 给定不同面额的硬币coins和一个总金额amount,编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,则返回-1。说明:你可以认为每种硬币的数量是无限的。 示例1: 输入:coins = [1, 2, 5], amount = 11 输出:3 解释:11 = …

如何使用Douglas-042为威胁搜索和事件应急响应提速

关于Douglas-042 Douglas-042是一款功能强大的PowerShell脚本,该脚本可以提升数据分类的速度,并辅助广大研究人员迅速从取证数据中筛选和提取出关键数据。 该工具能够搜索和识别Windows生态系统中潜在的安全漏洞,Douglas-042会将注意力放在…

Mistral发布语言大模型Mistral Large;法国新星Mistral挑战 OpenAI 霸主地位

🦉 AI新闻 🚀 Mistral发布语言大模型Mistral Large 摘要:Mistral Large 是 Mistral AI 公司最新发布的旗舰语言模型,具备顶尖水平的推理能力。它主要被设计用于处理复杂的多语言推理任务,比如文本理解、转换和代码生…

HTTP---------状态码

当服务端返回 HTTP 响应时,会带有一个状态码,用于表示特定的请求结果。比如 HTTP/1.1 200 OK,里面的 HTTP/1.1 表示协议版本,200 则是状态码,OK 则是对状态码的描述。 由协议版本、状态码、描述信息组成的行被称为起始…

【算法与数据结构】684、685、LeetCode冗余连接I II

文章目录 一、684、冗余连接 I二、685、冗余连接 II三、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、684、冗余连接 I 思路分析:题目给出一个无向有环图,要求去掉一个边以后构成一个树&#xf…

【iOS ARKit】ARWorldMap

ARWorldMap 用于存储 ARSession 检测扫描到的空间信息数据,包括地标(Landmark)、特征点(Feature Point)、平面(Plane)等,以及使用者的操作信息,如使用者添加的 ARAnchor …

【非比较排序】计算排序算法

目录 CountSort计数排序 整体思想 图解分析 代码实现 时间复杂度&优缺分析 CountSort计数排序 计数排序是一种非比较排序,不需要像前面的排序一样去比较。 计数排序的特性总结: 1. 计数排序在数据范围集中时,效率很高,但…

golang gin单独部署vue3.0前后端分离应用

概述 因为公司最近的项目前端使用vue 3.0,后端api使用golang gin框架。测试通过后,博文记录,用于备忘。 步骤 npm run build,构建出前端项目的dist目录,dist目录的结构具体如下图 将dist目录复制到后端程序同级目录…

Unity中URP下实现水体(水面高光)

文章目录 前言一、实现高光反射原理1、原理:2、公式: 二、实现1、定义 _SpecularColor 作为高光反射的颜色2、定义 _SpecularIntensity 作为反射系数,控制高光反射的强度3、定义 _Smoothness 作为高光指数,用于模型高光范围4、模拟…