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

JavaScript设计模式 -- 适配器模式

在软件开发中,经常会遇到这样的情况:现有的类或第三方库提供的接口与系统中期望的接口不匹配。如果直接修改已有代码风险较大或者不可行,这时适配器模式(Adapter Pattern)就能派上用场。适配器模式通过创建一个包装类,将原有接口转换为客户所期望的接口,从而使原本不兼容的类能够协同工作。

本文将从基本概念入手,详细介绍适配器模式的实现方式及其在多个场景下的应用示例,并探讨其优缺点和使用建议。

适配器模式简介

适配器模式是一种结构型设计模式,它的核心思想是通过一个中间层(适配器)将一个类的接口转换成客户期望的另一个接口,从而让原本接口不匹配的类能够一起工作。常见的应用场景包括:

  • 集成遗留系统:对接老系统时,接口可能与新系统不兼容;
  • 第三方库封装:使用外部库,但接口与项目需求不匹配;
  • 数据转换:不同数据格式之间的转换处理。

适配器模式既可以通过对象适配器(基于组合)实现,也可以通过类适配器(基于继承,多用于支持多重继承的语言)实现。由于 JavaScript 不支持多重继承,所以一般采用对象适配器的方式。


适配器模式的分类

  • 对象适配器
    通过在适配器中组合(引用)需要适配的对象,并在适配器内部调用其方法来完成转换。
  • 类适配器
    利用继承实现适配器,将目标接口与适配者接口组合在一起。
    (在 JavaScript 中,由于语言特性,通常采用对象适配器模式。)

适配器模式的实现示例

下面我们通过三个示例展示如何在不同场景下使用适配器模式解决接口不兼容问题。

示例 1:电源适配器

假设我们有一个旧设备只提供 connect() 方法,而新的电器要求使用 plugIn() 接口。我们可以使用适配器将旧设备的方法转换为新设备所期望的接口。

// 旧设备,只有 connect 方法
class OldDevice {connect() {console.log('旧设备已连接电源');}
}// 新设备接口期望 plugIn 方法
class NewDevice {plugIn() {console.log('新设备已插入电源');}
}// 适配器:将旧设备适配为新设备
class PowerAdapter {constructor(oldDevice) {this.oldDevice = oldDevice;}// 新设备所需的 plugIn 方法内部调用旧设备的 connect 方法plugIn() {this.oldDevice.connect();}
}// 客户端调用
const legacyDevice = new OldDevice();
const adapter = new PowerAdapter(legacyDevice);// 通过适配器使用旧设备
adapter.plugIn(); // 输出:旧设备已连接电源

在这个示例中,PowerAdapter 对象封装了旧设备的实例,并提供了客户期望的 plugIn() 方法,从而使不兼容的接口协同工作。


示例 2:数据格式适配器

在实际项目中,我们可能需要处理来自不同数据源的格式。例如,一个接口返回的用户数据格式与系统所需的格式不一致。我们可以使用适配器将旧数据格式转换成目标格式。

// 旧接口返回的数据格式
class OldUserAPI {getUser() {return {firstName: 'Jane',lastName: 'Doe'};}
}// 适配器:将旧数据格式转换为目标格式
class UserAdapter {constructor(oldApi) {this.oldApi = oldApi;}// 目标接口返回全名字符串getUserFullName() {const user = this.oldApi.getUser();return `${user.lastName}, ${user.firstName}`;}
}// 客户端调用
const oldUserApi = new OldUserAPI();
const userAdapter = new UserAdapter(oldUserApi);
console.log(userAdapter.getUserFullName()); // 输出:Doe, Jane

这里的 UserAdapter 将旧接口返回的对象转换为一个包含全名字符串的新格式,满足了系统的需求。


示例 3:第三方库接口适配

有时我们需要使用第三方库,但其回调式接口与我们项目中使用的 Promise 风格不匹配。可以通过适配器将回调式接口转换为 Promise 接口。

// 第三方库,采用回调方式获取数据
class ThirdPartyService {fetchData(callback) {setTimeout(() => {callback('数据来自第三方服务');}, 1000);}
}// 适配器:将回调式接口转换为 Promise 接口
class ServiceAdapter {constructor(service) {this.service = service;}fetchData() {return new Promise((resolve) => {this.service.fetchData((data) => {resolve(data);});});}
}// 客户端调用
const thirdPartyService = new ThirdPartyService();
const adapterService = new ServiceAdapter(thirdPartyService);adapterService.fetchData().then(data => {console.log(data); // 输出:数据来自第三方服务
});

在这个例子中,ServiceAdapter 封装了第三方服务,并将其回调式的 fetchData 方法转换为返回 Promise 的方法,从而方便与现代异步处理方式(如 async/await)配合使用。


适配器模式的优缺点

优点

  • 提高兼容性:适配器模式可以让原本不兼容的接口协同工作,方便系统集成和升级。
  • 复用现有类:无需修改现有类就能复用已有的功能代码。
  • 封装转换逻辑:将转换逻辑集中在适配器中,降低了系统其他部分的复杂度。

缺点

  • 增加系统复杂度:在简单情况下,使用适配器可能会增加系统的类数量,降低代码直观性。
  • 可能隐藏不匹配问题:适配器过多时,可能掩盖设计不当的根本原因,导致后续维护困难。

总结

适配器模式为解决接口不兼容问题提供了一种优雅的方案,无论是对接遗留系统、整合第三方库还是数据格式转换,均可通过创建适配器类来完成接口转换。本文通过电源适配器、数据格式适配器和第三方库接口适配三个示例,展示了如何在不同场景下运用适配器模式,并对其优缺点进行了分析。

希望这篇文章能帮助你在实际开发中正确识别并应用适配器模式,使系统各模块之间实现无缝协作。如果你有任何疑问或改进建议,欢迎在评论区交流分享!

相关文章:

JavaScript设计模式 -- 适配器模式

在软件开发中,经常会遇到这样的情况:现有的类或第三方库提供的接口与系统中期望的接口不匹配。如果直接修改已有代码风险较大或者不可行,这时适配器模式(Adapter Pattern)就能派上用场。适配器模式通过创建一个包装类&…...

Redis7.0八种数据结构底层原理

导读 本文介绍redis应用数据结构与物理存储结构,共八种应用数据结构和 一. 内部数据结构 1. sds sds是redis自己设计的字符串结构有以下特点: jemalloc内存管理预分配冗余空间二进制安全(c原生使用\0作为结尾标识,所以无法直接存储\0)动态计数类型(根据字符串长度动态选择…...

细说STM32F407单片机RTC的备份寄存器原理及使用方法

目录 一、备份寄存器的功能 二、示例功能 三、项目设置 1、晶振、DEBUG、CodeGenerator、USART6 2、RTC 3、NVIC 4、GPIO 及KEYLED 四、软件设计 1、main.h 2、main.c 3、rtc.c 4、keyled.c、keyled.h 五、运行调试 本实例旨在介绍备份寄存器的作用。本实例继续使…...

spring 学习 (注解)

目录 前言 常用的注解 须知 1 Conponent注解 demo(案例) 2 ControllerServiceRepository demo(案例) 3 ScopeLazyPostConstructPreDestroy demo(案例) 4 ValueAutowiredQualifierResource demo(案例) 5 Co…...

html+css设计情人节网页制作主页页面

制作一个情人节主题的网页主页是一个有趣的项目。以下是一个简单的HTML和CSS示例,帮助你开始。这个示例包括一个基本的情人节主题网页,包含标题、一些浪漫的背景图像、以及一些情人节相关的内容。 HTML部分 <!DOCTYPE html> <html lang="zh-CN"> <…...

【Linux】多线程 -> 从线程概念到线程控制

线程概念 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”。一切进程至少都有一个执行线程。线程在进程内部运行&#xff0c;本质是在进程地址空间内运行。在Linux系统中&#xff0c;在CPU眼…...

mapbox 从入门到精通 - 目录

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;mapbox 从入门到精通 文章目录 一、&#x1f340;总目录1.1 ☘️ mapbox基础1.2 ☘️…...

深度学习在半导体领域的创新点研究

摘要&#xff1a;本论文聚焦于深度学习在半导体领域的创新应用&#xff0c;全面剖析其为半导体产业带来的变革与机遇。通过深入探究深度学习在半导体设计、制造、测试及质量管控等多方面的创新实践&#xff0c;揭示其对提升半导体性能、降低成本及增强产业竞争力的关键作用。同…...

谈谈云计算、DeepSeek和哪吒

我不会硬蹭热点&#xff0c;去分析自己不擅长的跨专业内容&#xff0c;本文谈DeepSeek和哪吒&#xff0c;都是以这两个热点为引子&#xff0c;最终仍然在分析的云计算。 这只是个散文随笔&#xff0c;没有严谨的上下游关联关系&#xff0c;想到哪里就写到哪里。 “人心中的成见…...

redis cluster 增加节点 rebalance 的具体过程,如何做到不停值对外服务的

在 Redis 集群中增加节点并进行重新平衡&#xff08;rebalance&#xff09;的具体过程如下&#xff0c;并且在整个过程中可以做到不停机对外服务&#xff1a; 准备新节点&#xff1a; 新节点需要配置好 Redis 集群模式&#xff0c;并且确保可以与现有的集群节点通信。启动新节点…...

分享 UniApp 实现列表长按删除功能

在移动应用开发中&#xff0c;列表是常见的展示形式&#xff0c;而长按删除列表项也是一个实用且常见的交互功能。今天就来和大家分享如何在 UniApp 中实现列表的长按删除功能&#xff0c;同时附上详细的代码。 效果预览 通过代码实现后&#xff0c;我们将得到一个带有红色边…...

k8s集群搭建参考(by lqw)

文章目录 声明配置yum源安装docker安装 kubeadm&#xff0c;kubelet 和 kubectl部署主节点其他节点加入集群安装网络插件 声明 由于看了几个k8s的教程&#xff0c;都存在各种问题&#xff0c;自己搭建的时候&#xff0c;踩了不少坑&#xff0c;最后还是靠百度csdnchatGPT才搭建…...

vue知识点5

1.如何让组件里的样式与其他组件互相不干扰 scope范围的意思 <style scope> </style> 2.vue的生命周期 创建 挂载 更新 销毁 3.vue的四个生命周期详解 创建beforeCreate,created 挂载 beforeMount,mounted 更新 beforeUpdate,updated 销毁 beforeDest…...

「前端面试宝典」 - 猿媛之家(21.06)

模拟面试是提高个人沟通技巧的最有效方式 请记住&#xff1a;思维的深度&#xff0c;决定你人生的高度。胸怀的广度&#xff0c;决定你事业的长度。 面试官关注的重点不是题目的答案&#xff0c;而是求职者解题的思路与方法. 以排序算法为例&#xff1a;时间利用是否高效&#…...

poi 将图片写入到excel文件中

功能点说明 作用&#xff1a;将图片写入到指定的excel文件&#xff08;或output流&#xff09; 依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version> </dependen…...

C++算法竞赛基础语法-9

快速排序是一种高效的排序算法&#xff0c;由C. A. R. Hoare在1960年提出&#xff0c;基本思想是分治法&#xff08;Divide and Conquer&#xff09;策略&#xff0c;通过递归将一个大问题分解为若干个较小的子问题&#xff0c;然后合并这些子问题的解来解决原始问题 快速排序…...

Mac安装JD-GUI

Mac安装反编译工具步骤如下&#xff1a; 打开官网https://java-decompiler.github.io/ 选择下载mac的安装包解压下载好的压缩包&#xff0c;点击JD-GUI安装 有可能会遇到如下错误。请先检查是否安装JDK&#xff0c;通过java -version命令查看是否是1.8版本的jdk如果jdk没问题&…...

Nginx--日志(介绍、配置、日志轮转)

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 一、Nginx日志介绍 nginx 有一个非常灵活的日志记录模式&#xff0c;每个级别的配置可以有各自独立的访问日志, 所需日志模块 ngx_http_log_module 的…...

QML 快捷键与Shortcut的使用

一、效果展示 二、源码分享 import QtQuick import QtQuick.Controls import Qt.labs.qmlmodels import QtQuick.Controls.Basic import QtQuick.Layouts import QtQuick.Effects import Qt.labs.platformApplicationWindow {id:rootwidth: 1000height: 730visible: truetitle…...

制造业物联网的十大用例

预计到 2026 年&#xff0c;物联网制造市场价值将达到 4000 亿美元。实时收集和分析来自联网物联网设备与传感器的数据&#xff0c;这一能力为制造商提供了对生产流程前所未有的深入洞察。物联网&#xff08;IoT&#xff09;有潜力彻底改变制造业&#xff0c;使工厂能够更高效地…...

无人机遥感图像拼接及处理教程

无人机遥感图像采集流程&#xff1a; 无人机遥感监测 无人机航线规划设计 无人机飞行软件操作 无人机航拍一般过程 无人机遥感图像拼接软件&#xff1a; Photoscan软件 软件基本操作 遥感图像拼接的一般流程 遥感图像分组拼接与点云分类 无人机遥感图像拼接&#xff1a; 基于无…...

考研操作系统----操作系统的概念定义功能和目标(仅仅作为王道哔站课程讲义作用)

目录 操作系统的概念定义功能和目标 操作系统的四个特征 操作系统的分类 ​编辑 操作系统的运行机制 系统调用 操作系统体系结构 操作系统引导 虚拟机 操作系统的概念定义功能和目标 什么是操作系统&#xff1a; 操作系统是指控制和管理整个计算机系统的软硬件资源&…...

【以无克有】排序之随机快速排序

分治就是&#xff1a;抽刀断水水更流&#xff0c;举杯消愁愁更愁 文章目录 快速排序原理(最常见的双端扫描思路)原理讲解代码实现分区(Partition)部分&#xff1a;递归排序部分&#xff1a; 复杂度简要分析例题随机快速排序模板快排应用之第k小数(不去重) 参考资料及推荐总结 快…...

React源码解读

配置React源码本地调试环境 本次环境构建采用了node版本为16、react-scripts 版本号为 3.4.4&#xff0c;源码下载地址 react源码调试: react源码调试环境 使用 create-react-app 脚手架创建项目 npx create-react-app react-test 进入刚刚下载的目录&#xff0c;弹射 crea…...

[极客大挑战 2019]Havefun1

[极客大挑战 2019]Havefun1 代码审计发现 根据代码逻辑&#xff0c;要求传入’cat’参数&#xff0c;值为’dog’时执行if的操作&#xff0c;所以构造参数: ?catdog获得flag...

Ai人工智能的未来:趋势、挑战与机遇

Ai人工智能的未来&#xff1a;趋势、挑战与机遇 引言 人工智能&#xff08;AI&#xff09;已经成为当代科技发展的核心驱动力&#xff0c;其影响力渗透到各个行业&#xff0c;并塑造了我们未来的社会结构。无论是在医疗、金融、制造业&#xff0c;还是在自动驾驶、智能客服、…...

MG协议转换器:破解暖通设备通讯壁垒的智能钥匙

在智能化楼宇管理中&#xff0c;暖通空调系统&#xff08;HVAC&#xff09;的高效运行直接影响建筑的能耗控制与用户体验。然而&#xff0c;暖通设备品牌众多、协议不统一的问题长期困扰着运维人员&#xff1a;不同厂商的冷水机组、风机盘管、传感器等设备因采用Modbus、BACnet…...

【赵渝强老师】Spark的容错机制:检查点

由于Spark的计算是在内存中完成&#xff0c;因此任务执行的生命周期lineage&#xff08;血统&#xff09;越长&#xff0c;执行出错的概念就会越大。Spark通过检查点Checkpoint的方式&#xff0c;将RDD的状态写入磁盘进行持久化的保存从而支持容错。如果在检查点之后有节点出现…...

算法兵法全略(译文)

目录 始计篇 谋攻篇 军形篇 兵势篇 虚实篇 军争篇 九变篇 行军篇 地形篇 九地篇 火攻篇 用间篇 始计篇 算法&#xff0c;在当今时代&#xff0c;犹如国家关键的战略武器&#xff0c;也是处理各类事务的核心枢纽。算法的世界神秘且变化万千&#xff0c;不够贤能聪慧…...

react传递函数与回调函数原理

为什么 React 允许直接传递函数&#xff1f; 回调函数核心逻辑 例子&#xff1a;父组件控制 Modal 的显示与隐藏 // 父组件 (ParentComponent.tsx) import React, { useState } from react; import { Modal, Button } from antd; import ModalContent from ./ModalContent;co…...