设计模式 结构型 适配器模式(Adapter Pattern)与 常见技术框架应用 解析

在这里插入图片描述

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许将一个类的接口转换成客户端所期望的另一个接口,从而使原本因接口不兼容而无法一起工作的类能够协同工作。这种设计模式在软件开发中非常有用,尤其是在需要集成不同系统或库时,它们的接口可能并不一致。

一、核心思想

适配器模式的核心思想是通过创建一个中间层(适配器),使得原本由于接口不兼容而无法一起工作的类可以协同工作。这个中间层负责将源接口转换为目标接口,从而在客户端和目标类之间提供一个桥梁。

二、定义与结构

定义:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

结构

  • 目标接口(Target):定义了客户端期望的接口。
  • 被适配者(Adaptee):需要被适配的类,其接口与目标接口不兼容。
  • 适配器(Adapter):实现了目标接口,并持有被适配者的实例。适配器通过调用被适配者的方法来实现目标接口的方法。
角色

在适配器模式中,通常包含以下角色:

  • 目标角色(Target):定义了客户端需要使用的接口。
  • 源角色(Adaptee):需要被适配的接口,它与目标接口不兼容。
  • 适配器角色(Adapter):负责将源接口转换成目标接口,使得客户端可以通过目标接口与适配器交互,而无需知道具体的被适配者。
  • 客户类(Client):在客户类中针对目标抽象类进行编程,调用在目标抽象类中定义的业务方法。

三、实现步骤及代码示例

1、定义目标接口

public interface MediaPlayer {void play(String audioType, String fileName);
}

这里定义了一个简单的媒体播放器接口 MediaPlayer,它期望能播放指定音频类型和文件名的音频文件。

2、定义适配者类

public class AdvancedMediaPlayer {public void playVlc(String fileName) {System.out.println("Playing vlc file: " + fileName);}public void playMp4(String fileName) {System.out.println("Playing mp4 file: " + fileName);}
}

AdvancedMediaPlayer 是已有的高级媒体播放器类,能播放 VLCMP4 格式文件,但接口与 MediaPlayer 不同,是需要适配的对象。

3、实现适配器类

public class MediaAdapter implements MediaPlayer {private AdvancedMediaPlayer advancedMediaPlayer;public MediaAdapter(String audioType) {if ("vlc".equals(audioType)) {advancedMediaPlayer = new AdvancedMediaPlayer();advancedMediaPlayer.playVlc(audioType);} else if ("mp4".equals(audioType)) {advancedMediaPlayer = new AdvancedMediaPlayer();advancedMediaPlayer.playMp4(audioType);}}@Overridepublic void play(String audioType, String fileName) {if ("vlc".equals(audioType)) {advancedMediaPlayer.playVlc(fileName);} else if ("mp4".equals(audioType)) {advancedMediaPlayer.playMp4(fileName);}}
}

MediaAdapter 实现了 MediaPlayer 目标接口,内部根据传入音频类型实例化 AdvancedMediaPlayer,并在 play 方法中调用适配者对应方法来播放文件,完成接口适配。

4、客户端使用示例

public class AudioPlayer implements MediaPlayer {private MediaAdapter mediaAdapter;@Overridepublic void play(String audioType, String fileName) {if ("mp3".equals(audioType)) {System.out.println("Playing mp3 file: " + fileName);} else if (("vlc".equals(audioType)) || ("mp4".equals(audioType))) {mediaAdapter = new MediaAdapter(audioType);mediaAdapter.play(audioType, fileName);} else {System.out.println("Invalid audio type");}}
}public class Main {public static void main(String[] args) {AudioPlayer audioPlayer = new AudioPlayer();audioPlayer.play("mp3", "song.mp3");audioPlayer.play("vlc", "video.vlc");audioPlayer.play("mp4", "movie.mp4");}
}

AudioPlayer 作为客户端类,它本身能播放 MP3 文件,对于 VLCMP4 文件则借助 MediaAdapter 适配,在 main 程序入口,演示了多种音频格式播放,体现适配器模式使不同接口协同工作。

四、常见技术框架应用

1、在 Python 的 Django 框架中的应用

在 Django 项目中,若要整合第三方认证系统,其返回的用户数据格式与 Django 内置的用户模型格式不一致。假设第三方认证返回用户信息是一个字典 {"name": "John", "email": "john@example.com", "age": 30},而 Django 用户模型期望通过实例化 User 类,传入 usernameemail 等参数来创建用户。

from django.contrib.auth.models import User# 适配者类,模拟第三方认证返回数据格式
class ThirdPartyUserData:def __init__(self, user_data):self.user_data = user_datadef get_name(self):return self.user_data["name"]def get_email(self):return self.user_data["email"]def get_age(self):return self.user_data["age"]# 适配器类
class DjangoUserAdapter:def __init__(self, third_party_user_data):self.third_party_user_data = third_party_user_datadef create_django_user(self):name = self.third_party_user_data.get_name()email = self.third_party_user_data.get_email()username = name.lower().replace(" ", "")user = User.objects.create(username=username, email=email)return user# 客户端使用
third_party_user_data = ThirdPartyUserData({"name": "John Doe", "email": "johndoe@example.com", "age": 30})
adapter = DjangoUserAdapter(third_party_user_data)
new_user = adapter.create_django_user()
print(new_user)

这里 ThirdPartyUserData 是适配者,提供第三方原始用户数据格式。DjangoUserAdapter 是适配器,将第三方数据转换为符合 Django 用户模型创建的格式,使第三方认证能无缝接入 Django 项目。

2、在 JavaScript 的 Vue.js 框架中的应用

假设在 Vue 项目中有一个旧的图表组件 OldChart,它接收的数据格式是一个包含 labelsvalues 的二维数组 [["label1", "label2"], ["value1", "value2"]],但新的业务需求要求使用 echarts 库绘制图表,echarts 所需数据格式是一个对象 { xAxis: ["label1", "label2"], yAxis: ["value1", "value2"] }

<template><div id="app"><old-chart ref="oldChart" :data="oldData" /><echarts ref="echarts" :data="echartsData" /></div>
</template><script>
import OldChart from './OldChart.vue';
import echarts from 'echarts';// 适配者:旧图表组件
export default {components: { OldChart },data() {return {oldData: [["January", "February"], ["10", "20"]],echartsData: null};},mounted() {// 适配器const adapter = {convertData(oldData) {const [labels, values] = oldData;return { xAxis: labels, yAxis: values };}};const echartsData = adapter.convertData(this.oldData);this.echartsData = echartsData;const myChart = echarts.init(this.$refs.echarts.$el);myChart.setOption({xAxis: {type: 'category',data: echartsData.xAxis},yAxis: {type: 'value'},series: [{data: echartsData.yAxis,type: 'bar'}]});}
};
</script>

这里 OldChart 是适配者,adapterconvertData 方法作为适配器功能,将旧数据格式转换为 echarts 需要的格式,使两种图表组件能在同一项目中共存并按需使用。

五、应用场景

  1. 旧系统的兼容性问题:当需要使用一个已有系统,但它的接口与新系统不兼容时,可以通过适配器模式进行适配。
  2. 第三方库整合:当使用第三方库的接口与当前项目需求不一致时,可以通过适配器封装以符合需求。
  3. 统一接口:在多种类似功能的接口中,适配器可以对不同实现进行封装,提供统一的访问接口。
  4. 数据格式转换:在不同数据格式之间进行转换,如将JSON数据转换为XML数据。
  5. 硬件设备驱动:将不同厂商的硬件设备接口统一适配为系统标准接口。
  6. 图像绘制系统:现有一个老版本的绘图类LegacyRenderer,需要将其适配到新的绘图接口NewRenderer,以兼容新功能。
  7. 支付系统整合:整合多个第三方支付接口(如PayPal、Stripe)到统一的支付系统中。
  8. 日志框架适配器:将不同日志框架的接口统一适配为系统标准接口。
  9. 数据库适配器:将不同数据库供应商的API转换为统一的数据库访问接口,以便在不同的数据库之间切换和使用。
  10. 网络通信协议转换:在不同网络通信协议之间进行转换,如将HTTP请求转换为WebSocket请求。
  11. 操作系统平台差异处理:在不同操作系统平台(如Windows和Linux)之间进行文件路径或命令行参数的差异处理。
  12. 多媒体文件格式转换:在不同多媒体文件格式之间进行转换,如将MP3文件转换为WAV文件。
  13. 用户界面适配:在不同用户界面风格或布局之间进行适配,以满足不同用户的需求。
  14. 游戏控制器适配:将不同品牌或型号的游戏控制器适配为统一的游戏控制接口。
  15. 虚拟设备模拟:在软件开发过程中,模拟不存在的硬件设备或软件组件,以便进行测试或开发。
  16. 云服务集成:将不同云服务提供商的API转换为统一的接口,以便在多个云服务提供商之间无缝切换。
  17. 跨语言编程:在不同编程语言之间进行互操作,如将Java对象转换为Python对象。
  18. 消息队列集成:将不同消息队列系统的接口统一适配为系统标准接口。
  19. 缓存策略适配:将不同缓存策略的实现统一适配为系统标准接口。
  20. 安全认证机制适配:将不同安全认证机制的实现统一适配为系统标准接口。
  21. 国际化支持:将不同国际化方案的实现统一适配为系统标准接口。
  22. 时间日期格式转换:在不同时间日期格式之间进行转换,如将UNIX时间戳转换为人类可读的日期格式。
  23. 货币汇率转换:在不同货币之间进行汇率转换。
  24. 单位换算:在不同单位之间进行换算,如将英里转换为公里。
  25. 传感器数据适配:将不同传感器的数据格式统一适配为系统标准接口。
  26. 配置文件解析:将不同配置文件格式的解析结果统一适配为系统标准接口。

六、优缺点

优点

  1. 提高复用性:适配者类往往是已有且经过实践检验的代码,适配器模式让其能在新的目标接口场景下复用,避免重复开发类似功能。
  2. 增强系统扩展性:当需要接入新的不兼容模块或接口时,只需新增适配器类,无需改动原有系统核心代码,符合开闭原则,便于系统持续演进。
  3. 解耦系统组件:将接口转换逻辑封装在适配器中,使目标接口与适配者独立发展,降低两者直接耦合度,系统各部分维护、升级更便利。

缺点

  1. 额外的复杂性:引入适配器增加了系统类的数量与层次,如果过度使用,会使代码结构略显复杂,尤其在调试时,需追踪适配器内部逻辑及适配者原始接口,增加理解成本。
  2. 性能损耗:适配器在运行时需进行接口转换、数据格式调整等操作,相较于直接调用原生兼容接口,可能会有一定的性能损失,不过在多数非性能敏感场景下可接受。

在这里插入图片描述

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

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

相关文章

打造三甲医院人工智能矩阵新引擎(一):文本大模型篇--基于GPT-4o的探索

一、引言 当今时代,人工智能技术正以前所未有的速度蓬勃发展,深刻且广泛地渗透至各个领域,医疗行业更是这场变革的前沿阵地。在人口老龄化加剧、慢性疾病患病率上升以及人们对健康需求日益增长的大背景下,三甲医院作为医疗体系的核心力量,承担着极为繁重且复杂的医疗任务。…

S7-200采集频率信号

S7-200可以借助高速计数器完成频率信号采集&#xff0c;接入流量计、转速等信号。官方给出的程序块无法完成多路同时采集&#xff0c;需要自己进行修改。 首先下载官方的频率采集库 SIOS 下载后导入library&#xff0c;在library中出现Frequency(v1.0) 拖进ladder后&#xf…

专家混合(MoE)大语言模型:免费的嵌入模型新宠

专家混合&#xff08;MoE&#xff09;大语言模型&#xff1a;免费的嵌入模型新宠 今天&#xff0c;我们深入探讨一种备受瞩目的架构——专家混合&#xff08;Mixture-of-Experts&#xff0c;MoE&#xff09;大语言模型&#xff0c;它在嵌入模型领域展现出了独特的魅力。 一、M…

【Vue】分享一个快速入门的前端框架以及如何搭建

先上效果图: 登录 菜单: 下载地址: 链接&#xff1a;https://pan.baidu.com/s/1m-ZlBARWU6_2n8jZil_RAQ 提取码&#xff1a;ui20 … 主要是可以自定义设置token,更改后端请求地址较为方便。 应用设置: 登录与token设置: 在这里设置不用登录,可以请求的接口: request.js i…

MySQL叶子节点为啥使用双向链表?不使用单向呢?

文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ 文章内容收录到个人网站&#xff0c;方便阅读&#xff1a;http://hardyfish.top/ MySQL 中的 B 树索引&#x…

用户界面的UML建模10

非正常的可视反馈可伴随着同步事件发生&#xff0c;而同步事件可由系统动作产生。但是&#xff0c;可以分别对它们进行建模。 在下节中将对这些特殊的事件依次进行论述。 6.1 异常处理建模 异常&#xff0c;由Meyer 定义[16],其作为运行时事件&#xff08;run-time events&a…

最新版Chrome浏览器加载ActiveX控件之CFCA安全输入控件

背景 CFCA安全输入控件用于保证用户在浏览器、桌面客户端、移动客户端中输入信息的安全性&#xff0c;防止运行在用户系统上的病毒、木马等恶意程序入侵窃取用户输入的敏感信息。确保用户输入、本地缓存、网络传输整个流程中&#xff0c;输入的敏感信息不被窃取。广泛应用于银行…

0基础跟德姆(dom)一起学AI 自然语言处理10-LSTM模型

1 LSTM介绍 LSTM&#xff08;Long Short-Term Memory&#xff09;也称长短时记忆结构, 它是传统RNN的变体, 与经典RNN相比能够有效捕捉长序列之间的语义关联, 缓解梯度消失或爆炸现象. 同时LSTM的结构更复杂, 它的核心结构可以分为四个部分去解析: 遗忘门输入门细胞状态输出门…

力扣283 移动零

void moveZeroes(int* nums, int numsSize) {int last_non_zero_found_at 0;for (int i 0; i < numsSize; i) {if (nums[i] ! 0) {// 交换 nums[last_non_zero_found_at] 和 nums[i]int temp nums[last_non_zero_found_at];nums[last_non_zero_found_at] nums[i];nums[i…

LookingGlass使用

文章目录 背景编译安装运行限制使用场景总结参考 背景 Looking Glass 是一款开源应用程序&#xff0c;可以直接使用显卡直通的windows虚拟机。 常见环境是Linux hostwindows guest&#xff0c;基本部署结构图&#xff1a; 编译 git clone --recursive https://github.com/g…

JVM学习:CMS和G1收集器浅析

总框架 一、Java自动内存管理基础 1、运行时数据区 运行时数据区可分为线程隔离和线程共享两个维度&#xff0c;垃圾回收主要是针对堆内存进行回收 &#xff08;1&#xff09;线程隔离 程序计数器 虚拟机多线程是通过线程轮流切换、分配处理器执行时间来实现的。为了线程切换…

关于 webservice 日志中 源IP是node IP的问题,是否能解决换成 真实的客户端IP呢

本篇目录 1. 问题背景2. 部署gitlab 17.52.1 添加repo源2.2 添加repo源 下载17.5.0的charts包2.3 修改values文件2.3.1 hosts修改如下2.3.2 appConfig修改如下2.3.3 gitlab下的sidekiq配置2.3.4 certmanager修改如下2.3.5 nginx-ingress修改如下2.3.6 <可选> prometheus修…

javaEE-网络编程-3 UDP

目录 Socaket套接字 UDP数据报套字节编程 1.DatagrameSocket类 DatagramSocaket构造方法: DatagramSocaket常用方法&#xff1a; 2.DatagramPacket类 DatagramPacket构造方法&#xff1a; UDP回显服务器实现 UDP服务端实现&#xff1a; 创建一个Socket类对象&#xf…

【Vim Masterclass 笔记08】第 6 章:Vim 中的文本变换及替换操作 + S06L20:文本的插入、变更、替换,以及合并操作

文章目录 Section 6&#xff1a;Transforming and Substituting TextS06L21 Inserting, Changing, Replacing, and Joining1 定位到行首非空字符&#xff0c;并启用插入模式2 在紧挨光标的下一个字符位置启动插入模式3 定位到一行末尾&#xff0c;并启用插入模式4 定位到光标的…

Transformer知识梳理

Transformer知识梳理 文章目录 Transformer知识梳理什么是Transformer&#xff1f;语言模型迁移学习 Transformer结构注意力层原始结构 总结 什么是Transformer&#xff1f; 语言模型 Transformer模型本质上都是预训练语言模型&#xff0c;大部分采用自监督学习&#xff08;S…

小程序学习06——uniapp组件常规引入和easycom引入语法

目录 一 组件注册 1.1 组件全局注册 1.2 组件全局引入 1.3 组件局部引入 页面引入组件方式 1.3.1 传统vue规范&#xff1a; 1.3.2 通过uni-app的easycom 二 组件的类型 2.1 基础组件列表 一 组件注册 1.1 组件全局注册 &#xff08;a&#xff09;新建compoents文件…

数据插入操作的深度分析:INSERT 语句使用及实践

title: 数据插入操作的深度分析:INSERT 语句使用及实践 date: 2025/1/5 updated: 2025/1/5 author: cmdragon excerpt: 在数据库管理系统中,数据插入(INSERT)操作是数据持久化的基础,也是应用程序与用户交互的核心功能之一。它不仅影响数据的完整性与一致性,还在数据建…

并发服务器框架——zinx

zinx框架 Zinx 是一个用 Go 语言编写的高性能、轻量级的 TCP 服务器框架&#xff0c;它被设计为简单、快速且易于使用。Zinx 提供了一系列的功能&#xff0c;包括但不限于连接管理、数据编解码、业务处理、负载均衡等&#xff0c;适用于构建各种 TCP 网络服务&#xff0c;如游戏…

科研绘图系列:R语言科研绘图之标记热图(heatmap)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图系统信息参考介绍 科研绘图系列:R语言科研绘图之标记热图(heatmap) 加载R包 library(tidyverse) library(ggplot2) library(reshape)…

物体切割效果

1、物体切割效果是什么 在游戏开发中&#xff0c;物体切割效果就是物体看似被切割、分割或隐藏一部分的视觉效果。 这种效果常用与游戏和动画中&#xff0c;比如角色攻击时的切割效果&#xff0c;场景中的墙壁切割效果等等。 2、物体切割效果的基本原理 在片元着色器中判断片…