当前位置: 首页 > news >正文

4.结构型设计模式 - 第1回:引言与适配器模式 (Adapter Pattern) ——设计模式入门系列

一、引言

在现代软件开发中,设计模式是帮助我们解决复杂问题的工具,它们提供了在常见场景下重用已验证解决方案的途径。而结构型设计模式主要关注类与对象之间的组合方式,旨在通过增强灵活性和降低耦合度来改进代码的结构。

本次讨论的是结构型模式中的第一个:适配器模式 (Adapter Pattern)。它的核心目的是使接口不兼容的类能够协同工作,充当两个类之间的桥梁,保证代码的可扩展性和复用性。

二、适配器模式概述

1. 定义

适配器模式(Adapter Pattern)将一个类的接口转换为客户期望的另一个接口,使得原本接口不兼容的类可以一起工作。它常用于解决“现有接口”与“需要的接口”之间的不兼容问题。

2. 使用场景

适配器模式适用于以下场景:

  • 你希望使用一个现有的类,而它的接口并不符合你的需求。
  • 创建一个可以与多个不相关类协同工作的类,而不修改这些类的接口。

三、适配器模式的结构

适配器模式可以以类适配器和对象适配器两种方式实现:

  1. 类适配器:通过继承的方式实现适配,利用多继承模拟适配。
  2. 对象适配器:通过组合(持有被适配对象的实例)实现适配。
类图:
+--------------------------------+
|           客户端(Client)      |
+--------------------------------+| 使用目标接口v
+--------------------------------+
|           目标接口(Target)   |<-----+
+--------------------------------+      |^                           | 实现目标接口|                           |
+--------------------------------+       |
|           适配器(Adapter)    |-------+ 
| 适配器实现目标接口,并调用被适配对象 |
+--------------------------------+|v
+--------------------------------+
|        被适配者(Adaptee)     |
+--------------------------------+

四、代码实现

以下是一个简单的 Java 示例,展示如何将一个老旧的系统接口适配成新的系统接口。

1. 被适配类 (Adaptee)

// 现有类,无法直接改变
public class LegacyPrinter {public void printText(String text) {System.out.println("Legacy Printer: " + text);}
}

2. 目标接口 (Target)

// 客户端期望的接口
public interface Printer {void print(String message);
}

3. 适配器类 (Adapter)

// 通过适配器将旧的 LegacyPrinter 适配为 Printer 接口
public class PrinterAdapter implements Printer {private LegacyPrinter legacyPrinter;public PrinterAdapter(LegacyPrinter legacyPrinter) {this.legacyPrinter = legacyPrinter;}@Overridepublic void print(String message) {legacyPrinter.printText(message);}
}

4. 客户端代码 (Client)

public class Client {public static void main(String[] args) {Printer printer = new PrinterAdapter(new LegacyPrinter());printer.print("Hello, Adapter Pattern!");}
}

五、类适配器 vs 对象适配器

适配器类型特点优缺点
类适配器通过继承实现,适配器类同时继承了目标接口和被适配者类。优点:简洁,适合单一类适配。缺点:不支持多个类适配,受限于 Java 单继承机制。
对象适配器通过组合实现,适配器类包含一个被适配者类的实例,并实现目标接口。优点:更灵活,支持多个类的适配。缺点:稍微增加了间接层次。

六、案例分析

1. 现实生活案例:电源适配器

一个常见的现实生活中的例子是电源适配器。不同国家的电压标准和插头形状不同,电器设备无法直接使用。但通过电源适配器,电压和插头形状都能被转换为设备所需的标准,从而确保设备正常工作。

2. 综合案例:数据库连接适配器

假设我们有一个旧版数据库系统,它的连接接口已经过时,但现在我们希望在新的系统中使用不同的数据库连接接口。

// 旧版数据库系统
public class OldDatabase {public void connectToDb(String connectionString) {System.out.println("Connecting to database with " + connectionString);}
}// 新系统期望的数据库接口
public interface Database {void connect(String databaseUrl);
}// 适配器,将老接口适配为新接口
public class DatabaseAdapter implements Database {private OldDatabase oldDatabase;public DatabaseAdapter(OldDatabase oldDatabase) {this.oldDatabase = oldDatabase;}@Overridepublic void connect(String databaseUrl) {oldDatabase.connectToDb(databaseUrl);}
}// 客户端代码
public class Client {public static void main(String[] args) {Database db = new DatabaseAdapter(new OldDatabase());db.connect("jdbc:mysql://localhost:3306/mydb");}
}

七、补充与开发建议

在实际开发中,适配器模式是处理代码重构、引入第三方库或与遗留系统集成的有效手段。但在使用适配器时应注意以下几点:

  1. 谨慎过度使用:适配器模式容易滥用,如果系统中出现了大量的适配器类,可能预示着系统设计不够清晰。
  2. 适配的范围:当接口之间差异较大时,使用适配器可能会增加系统复杂性。最好将适配的范围控制在接口定义和调用的边界。
  3. 保持灵活性:为了保持代码的灵活性,可以结合其他模式,如工厂模式,通过工厂创建适配器实例。

八、结论

适配器模式是一种强大的模式,能够在保持原有类功能的同时,使其符合新的需求。通过合理使用,能够增强系统的兼容性和可扩展性。在架构演进和系统重构中,适配器模式是开发人员不可或缺的工具之一。


相关阅读

  • 设计模式入门系列

相关文章:

4.结构型设计模式 - 第1回:引言与适配器模式 (Adapter Pattern) ——设计模式入门系列

一、引言 在现代软件开发中&#xff0c;设计模式是帮助我们解决复杂问题的工具&#xff0c;它们提供了在常见场景下重用已验证解决方案的途径。而结构型设计模式主要关注类与对象之间的组合方式&#xff0c;旨在通过增强灵活性和降低耦合度来改进代码的结构。 本次讨论的是结…...

解决mybatis plus 中 FastjsonTypeHandler无法正确反序列化List类型的问题

由于是根据自动映射类型&#xff0c;我们设置的字段类型是List 也就是反序列化的时候也只是用 FastjsonTypeHandler中的 Override protected Object parse(String json) { return JSON.parseObject(json, type); } 反序列化方法&#xff0c;这是type为List 反序列后我们并没…...

MacOS安装homebrew,jEnv,多版本JDK

1 安装homebrew homebrew官网 根据官网提示&#xff0c;运行安装命令 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"安装后&#xff0c;bash会提示执行两条命令 (echo; echo eval "$(/opt/homebrew/b…...

【HTTP】认识 URL 和 URL encode

文章目录 认识 URLURL 基本格式**带层次的文件路径****查询字符串****片段标识符** URL encode 认识 URL 计算机中非常重要的概念&#xff0c;并不仅仅是在 HTTP 中使用。用来描述一个网络资源所处的位置&#xff0c;全称“唯一资源定位符” URI 是“唯一资源标识符“严格的说…...

【AI学习笔记】初学机器学习西瓜书概要记录(二)常用的机器学习方法篇

初学机器学习西瓜书的概要记录&#xff08;一&#xff09;机器学习基础知识篇(已完结) 初学机器学习西瓜书的概要记录&#xff08;二&#xff09;常用的机器学习方法篇(持续更新) 初学机器学习西瓜书的概要记录&#xff08;三&#xff09;进阶知识篇(待更) 文字公式撰写不易&am…...

[SDX35+WCN6856]SDX35 + WCN6856 默认增加打包wifi配置hostapd_24g.conf和hostapd_5g.conf操作方法

SDX35 SDX35介绍 SDX35设备是一种多模调制解调器芯片,支持 4G/5G sub-6 技术。它是一个4nm芯片专为实现卓越的性能和能效而设计。它包括一个 1.9 GHz Cortex-A7 应用处理器。 SDX35主要特性 ■ 3GPP Rel. 17 with 5G Reduced Capability (RedCap) support. Backward compati…...

【iOS】OC高级编程 iOS多线程与内存管理阅读笔记——自动引用计数

文章目录 什么是自动引用计数 内存管理/引用计数 概要 内存管理的思考方式 自己生成的对象&#xff0c;自己所持有 非自己生成的对象&#xff0c;自己也能持有 不再需要自己持有的对象时释放 无法释放非自己持有的对象 什么是自动引用计数 自动引用计数&#xff08;AR…...

网络安全-LD_PRELOAD,请求劫持

目录 一、环境 二、开始做题 三、总结原理 四、如何防护 一、环境 我们这里用蚁剑自带的靶场第一关来解释 docker制作一下即可 二、开始做题 首先环境内很明显给我们已经写好了webshell 同样我们也可以访问到 我们使用这个蚁剑把这个webshell连上 我们发现命令不能执行&am…...

GO入门之值传递于引用(指针、内存地址)传递扫盲

GO入门之值传递于引用&#xff08;指针、内存地址&#xff09;传递扫盲 Go 语言中&#xff0c;值传递和引用&#xff08;指针&#xff09;传递是两个关键的概念。通过案例可以很好地展示两者的区别。 值传递与引用传递的区别&#xff1a; 值传递&#xff1a;传递的是变量的副…...

【渗透测试】-vulnhub源码框架漏洞-Os-hackNos-1

vulnhub源码框架漏洞中的CVE-2018-7600-Drupal 7.57 文章目录  前言 1.靶场搭建&#xff1a; 2.信息搜集&#xff1a; 主机探测&#xff1a; 端口扫描&#xff1a; 目录扫描&#xff1a; 3.分析&#xff1a; 4.步骤&#xff1a; 1.下载CVE-2018-7600的exp 2.执行exp: 3.写入木…...

sqli-lab靶场学习(三)——Less8-10(盲注、时间盲注)

Less8 第八关依然是先看一般状态 http://localhost/sqli-labs/Less-8/?id1 然后用单引号闭合&#xff1a; http://localhost/sqli-labs/Less-8/?id1 这关的问题在于报错是不显示&#xff0c;那没办法通过上篇文章的updatexml大法处理。对于这种情况&#xff0c;需要用“盲…...

Pybullet 安装过程

Pybullet 安装过程&#xff08;windows&#xff09; 1. 安装C编译工具2. 安装Pybullet 1. 安装C编译工具 pybullet 需要C编译套件&#xff0c;直接装之前检查下&#xff0c;要不会报缺少某版本MVSC的error&#xff0c;最好的方式是直接下载visual studio&#xff0c;直接按默认…...

Error when custom data is added to Azure OpenAI Service Deployment

题意&#xff1a;在向 Azure OpenAI 服务部署添加自定义数据时出现错误。 问题背景&#xff1a; I receive the following error when adding my custom data which is a .txt file (it doesnt matter whether I add it via Azure Cognitive Search, Azure Blob Storage, or F…...

libreoffice word转pdf

一、准备一个word文件 运行&#xff1a; cd /root libreoffice --headless --convert-to pdf --outdir /root/output doc1.docx 发现中文乱码&#xff1a; 此时我们需要给linux 上添加中文字体&#xff1a; centos7 添加中文字体 再次运行正常&#xff1a; libreoffice --h…...

java -----泛型

泛型的理解和好处 泛型是在JDK5之后引入的一个新特性&#xff0c;可以在编译阶段约束操作的数据类型&#xff0c;并进行检查。 泛型的格式为 <数据类型> import java.util.ArrayList;SuppressWarnings({"all"}) public class Generic02 {public static void…...

Springboot 文件上传下载相关问题

文章目录 关于Springboot 文件上传下载问题解决方案注意事项文件上传文件下载文件删除文件在线打开在写练习的时候&#xff0c;发现了一些小小的问题&#xff0c;已经在 上述代码中体现。① 代码路径碰到中文的时候&#xff0c;会有乱码&#xff0c;需要转换&#xff08;内容中…...

【Kotlin 与 Java 互操作】Java中调用带有默认值的Kotlin函数(十四)

导读大纲 1.0.1 Java 没有默认参数值的概念1.0.2 使用 JvmOverloads 来简化调用 1.0.1 Java 没有默认参数值的概念 因此当从 Java 调用带有默认参数值的 Kotlin 函数时 1. 必须明确指定所有参数值 fun <T> joinToString(collection: Collection<T>,separator: St…...

点赞系统实现

点赞功能是社交、电商等几乎所有的互联网项目中都广泛使用。虽然看起来简单&#xff0c;不过蕴含的技术方案和手段还是比较多的。 下面将分享之前做的判题OJ系统的点赞系统的思路。 1.需求分析 点赞功能与其它功能不同&#xff0c;没有复杂的原型和需求&#xff0c;仅仅是一…...

c++进阶学习-----继承

1.继承的概念及定义 1.1继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特性的基础上进行扩展&#xff0c;增加功能&#xff0c;这样产生新的类&#xff0c;称派生类。 继承呈现了面向对象 程序设计的…...

C++学习笔记(37)

302、makefile 在实际开发中&#xff0c;项目的源代码文件比较多&#xff0c;按类型、功能、模块分别存放在不同的目录和文件中&#xff0c;哪 些文件需要先编译&#xff0c;那些文件后编译&#xff0c;那些文件需要重新编译&#xff0c;还有更多更复杂的操作。 make 是一个强大…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

【JVM】- 内存结构

引言 JVM&#xff1a;Java Virtual Machine 定义&#xff1a;Java虚拟机&#xff0c;Java二进制字节码的运行环境好处&#xff1a; 一次编写&#xff0c;到处运行自动内存管理&#xff0c;垃圾回收的功能数组下标越界检查&#xff08;会抛异常&#xff0c;不会覆盖到其他代码…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

Ascend NPU上适配Step-Audio模型

1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统&#xff0c;支持多语言对话&#xff08;如 中文&#xff0c;英文&#xff0c;日语&#xff09;&#xff0c;语音情感&#xff08;如 开心&#xff0c;悲伤&#xff09;&#x…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...