设计模式精讲 Day 6:适配器模式(Adapter Pattern)

【设计模式精讲 Day 6】适配器模式(Adapter Pattern)


文章内容

在“设计模式精讲”系列的第6天,我们将深入讲解适配器模式(Adapter Pattern)。作为结构型设计模式之一,适配器模式的核心思想是将一个类的接口转换成客户期望的另一个接口,使得原本不兼容的类可以协同工作。

适配器模式广泛应用于系统集成、遗留系统改造、第三方库对接等场景中,尤其在需要兼容不同接口或协议时非常实用。通过本文的学习,你将掌握适配器模式的基本原理、实现方式、适用场景,并了解它在 Java 标准库和实际项目中的应用。


模式定义

适配器模式是一种结构型设计模式,它通过封装一个已有对象,使其接口与目标接口兼容,从而允许不兼容的类之间进行协作。

其核心思想是:通过中间层(适配器)将现有类的接口转换为客户端所期望的接口。适配器可以是类适配器(继承方式)或对象适配器(组合方式),具体选择取决于设计需求。


模式结构

适配器模式的 UML 类图包含以下几个关键角色:

  • Target(目标接口):客户端使用的接口。
  • Adaptee(被适配者):已有接口,与目标接口不兼容。
  • Adapter(适配器):实现目标接口,并包装 Adaptee 实例,使两者兼容。

文字描述如下:

  1. Target 是客户端期望使用的接口,通常是一个抽象类或接口。
  2. Adaptee 是已有的类,其接口与 Target 不兼容。
  3. Adapter 是适配器类,它实现了 Target 接口,并内部持有 Adaptee 的引用,通过调用 Adaptee 的方法来满足 Target 的需求。

适用场景

场景描述
接口不兼容当两个类的接口不一致,但希望它们能够协作时。
系统集成在整合多个子系统或第三方服务时,适配器可以统一接口。
遗留系统改造将旧系统接口适配为新系统所需格式,避免大规模重构。
多种数据源支持例如数据库适配器、文件适配器等,统一访问不同数据源。

例如,在开发支付系统时,可能需要适配支付宝、微信、银联等多个支付平台的接口,适配器模式可以统一这些接口,简化客户端代码。


实现方式

下面是一个完整的 Java 示例,展示适配器模式的两种实现方式:类适配器对象适配器

1. 定义目标接口(Target)
// 目标接口:客户端期望的接口
public interface MediaPlayer {void play(String audioType, String fileName);
}
2. 定义被适配者(Adaptee)
// 被适配者:已有接口,与目标接口不兼容
public class AdvancedMediaPlayer {public void playVlc(String fileName) {System.out.println("播放 VLC 文件: " + fileName);}public void playMp4(String fileName) {System.out.println("播放 MP4 文件: " + fileName);}
}
3. 实现适配器(Adapter)
类适配器(继承方式)
// 类适配器:继承 Adaptee 并实现 Target 接口
public class VlcPlayerAdapter extends AdvancedMediaPlayer implements MediaPlayer {@Overridepublic void play(String audioType, String fileName) {if ("vlc".equalsIgnoreCase(audioType)) {playVlc(fileName);} else {System.out.println("不支持的音频格式: " + audioType);}}
}
对象适配器(组合方式)
// 对象适配器:组合 Adaptee 并实现 Target 接口
public class Mp4PlayerAdapter implements MediaPlayer {private AdvancedMediaPlayer mediaPlayer;public Mp4PlayerAdapter() {this.mediaPlayer = new AdvancedMediaPlayer();}@Overridepublic void play(String audioType, String fileName) {if ("mp4".equalsIgnoreCase(audioType)) {mediaPlayer.playMp4(fileName);} else {System.out.println("不支持的音频格式: " + audioType);}}
}
4. 客户端使用示例
public class Client {public static void main(String[] args) {// 使用类适配器MediaPlayer vlcPlayer = new VlcPlayerAdapter();vlcPlayer.play("vlc", "movie.vlc");// 使用对象适配器MediaPlayer mp4Player = new Mp4PlayerAdapter();mp4Player.play("mp4", "video.mp4");}
}

输出结果:

播放 VLC 文件: movie.vlc
播放 MP4 文件: video.mp4

工作原理

适配器模式的核心机制是接口转换,即通过适配器将原有类的接口“翻译”为目标接口。其底层逻辑如下:

  1. 客户端调用目标接口的方法
  2. 适配器接收到请求后,将其转发给被适配者的相应方法
  3. 被适配者执行操作并返回结果
  4. 适配器将结果返回给客户端

这种机制使得客户端无需关心被适配者的具体实现,只需关注目标接口即可。


优缺点分析

优点缺点
提高系统的兼容性,解决接口不匹配问题增加了系统复杂度,需额外编写适配器类
降低模块之间的耦合度过度使用适配器可能导致代码臃肿
支持多种接口转换,提高扩展性无法处理所有类型接口的转换,需按需实现

案例分析:支付系统适配器

假设我们正在开发一个电商平台,需要集成多个支付平台(如支付宝、微信、银联)。每个平台的接口都不同,直接调用会增加耦合度,维护成本高。

问题:

  • 各个支付平台的接口不一致。
  • 客户端代码需要针对不同平台写不同的调用逻辑。

解决方案:

  • 创建统一的 Payment 接口。
  • 为每个支付平台实现适配器类,将各自的接口适配为 Payment 接口。
  • 客户端只需调用 Payment 接口,无需关心具体实现。

代码示例:

// 统一支付接口
public interface Payment {boolean pay(double amount);
}// 支付宝适配器
public class AlipayAdapter implements Payment {private Alipay alipay;public AlipayAdapter() {this.alipay = new Alipay();}@Overridepublic boolean pay(double amount) {return alipay.processPayment(amount);}
}// 微信支付适配器
public class WeChatPayAdapter implements Payment {private WeChatPay weChatPay;public WeChatPayAdapter() {this.weChatPay = new WeChatPay();}@Overridepublic boolean pay(double amount) {return weChatPay.transfer(amount);}
}

客户端使用:

public class PaymentClient {public static void main(String[] args) {Payment alipay = new AlipayAdapter();alipay.pay(100.0);Payment wechat = new WeChatPayAdapter();wechat.pay(50.0);}
}

与其他模式的关系

模式关系说明
代理模式两者都涉及对对象的封装,但代理模式用于控制访问,而适配器模式用于接口转换。
装饰器模式装饰器模式用于动态添加功能,而适配器模式用于接口兼容。
桥接模式桥接模式分离抽象与实现,而适配器模式用于接口适配,二者目的不同。

适配器模式常与工厂模式结合使用,用于统一创建不同类型的适配器对象,提升系统灵活性。


总结

适配器模式是一种强大的结构型设计模式,通过接口转换解决了系统间兼容性问题。它在系统集成、遗留系统改造、第三方库对接等场景中具有广泛应用价值。

在本篇文章中,我们详细介绍了适配器模式的定义、结构、实现方式、工作原理、优缺点以及实际应用场景。通过 Java 代码示例,我们展示了如何使用类适配器和对象适配器来实现接口转换,并结合支付系统案例说明其在实际项目中的作用。

下一节我们将进入“设计模式精讲”的第7天,讲解桥接模式(Bridge Pattern),它是结构型设计模式中的一种,用于解耦抽象与实现,提升系统的可扩展性。


文章标签

design-patterns, java, software-engineering, oop, object-oriented-programming, adapter-pattern, design-pattern-day6


文章简述

在“设计模式精讲”系列的第6天,我们深入讲解了适配器模式(Adapter Pattern),这是一种结构型设计模式,旨在解决接口不兼容的问题。文章从理论到实践全面解析了该模式的定义、结构、适用场景、实现方式,并结合真实项目案例说明其应用价值。我们通过完整的 Java 代码示例展示了类适配器和对象适配器的实现方式,并讨论了其在支付系统等实际场景中的应用。此外,还分析了适配器模式与其他设计模式的关系,以及其优缺点。通过本文的学习,读者将掌握如何在实际项目中高效地使用适配器模式,提升系统的兼容性和可维护性。


进一步学习资料

  1. Design Patterns: Elements of Reusable Object-Oriented Software
  2. Java Design Patterns - A Hands-On Guide with Examples
  3. Refactoring Guru - Adapter Pattern
  4. Java 中的适配器模式详解
  5. Java Design Patterns: Adapter Pattern in Practice

核心设计思想回顾

  • 适配器模式通过接口转换解决系统间的兼容性问题。
  • 具有类适配器和对象适配器两种实现方式,可根据需求选择。
  • 在实际项目中,常用于系统集成、遗留系统改造、多支付平台对接等场景。
  • 与代理模式、装饰器模式、桥接模式等有密切关系,可结合使用提升系统灵活性。
  • 适用于接口不一致、需要兼容多个系统或服务的场景。

在实际开发中,合理使用适配器模式可以显著提升系统的可维护性和扩展性,特别是在面对复杂系统集成时。

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

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

相关文章

系统稳定性治理

一、微服务内部异常 描述 微服务Pod自动重启表现:服务波动(响应时间不稳定)、监控指标异常(Pod重启次数增加,CPU/内存波动)、Kubernetes事件记录容器重启原因影响:服务中断、性能波动、资源消耗…

多智能体协同的力量:赋能AI安全报告系统的智能设计之道

“设想一个由‘数据采集者’、‘风险分析师’、‘报告撰写员’甚至‘合规监督员’组成的虚拟团队,它们如何携手打造一份深度洞察、精准预警的危化安全报告?这正是多智能体协作在AI安全领域的魅力所在。” 一、挑战升级:单一AI难以应对的复杂性…

ceph pg 卡在 active+clean+remapped 状态

场景 ceph 环境中有个 osd.0 做了 raid0 ,后来想剔除掉,执行了 ceph osd out 0 然后等了很长时间等 pg 数据迁移到别的 osd,但是最后有一个 pg 状态卡在了 active+clean+remapped 状态。如下: ceph pg ls-by-osd 0 PG OBJECTS DEGRADED MISPLACED UNFOUND BYTES …

systemd[1]: Failed to start LSB: Bring up/down networking

使用ssh连接虚拟机服务时,连接异常,虚拟机系统centos 7,于是登录虚拟机,查看服务ip,发现配置的静态ip未生效。因此重启网卡systemctl restart network,出现报错,使用systemctl status network查…

Go 语言使用 excelize 库操作 Excel 的方法

在笔者开发的项目中,有操作excel的需要,由于go操作excel比较方便且功能强大,于是选择使用go来操作excel。github.com/360EntSecGroup-Skylar/excelize库是一个功能强大且易于使用的库,它支持创建、读取和修改 Excel 文件&#xff…

Java基础(三):逻辑运算符详解

Java基础系列文章 Java基础(一):发展史、技术体系与JDK环境配置详解 Java基础(二):八种基本数据类型详解 Java基础(三):逻辑运算符详解 目录 一、什么是逻辑运算符?二、基础逻辑运算符(3种)1、&&…

Bugku-CTF-web

最近刷了一下 Bugku-CTF-web 的61-70题(平台目前只有67),好难好难,全都是知识的盲区。各种代码审计,各种反序列化,各种反弹shell,各种模版注入,各种字符串绕过,可以说是W…

GitLab 工具如何提升我的工作效率

在当今快节奏的软件开发和技术创作领域,作为一名博主,高效的工作流程和强大的协作工具至关重要。GitLab 作为一款集成了版本控制、项目管理、持续集成与持续部署(CI/CD)等功能于一体的平台,为我的工作带来了巨大的便利…

Unity Addressable使用之服务器远程加载

本地模拟服务器加载 1、创建一个Profiles,将Remote设为Editor Hosted 2、在Addressables Group窗口将Profile设为Local Test 3、将某个Asset Groups设为Remote加载 4、Build资源 5、打开本地模拟服务器 Addressables Hosting 窗口是 Addressable 提供的一个内置本…

Java基础八股文 - 面试者心理历程与标准答案

Java基础八股文 - 面试者心理历程与标准答案 前言:如何应对Java基础面试问题 面试Java基础时,很多候选人会因为紧张而忘记平时熟悉的知识点。本文将从面试者的心理历程出发,教你如何在面试中用自己的思路组织答案,然后给出标准回…

学习笔记088——Windows配置Tomcat自启

1、下载 下载Windows版本tomcat。本文下载的版本是: apache-tomcat-9.0.31-windows-x64.zip 点击下载 注意:要确保bin目录下有 service.bat 文件! 2、配置服务 解压后,终端进入bin⽬录,安装服务:service…

SSL证书怎么配置到服务器上 ?

在网络安全备受关注的当下,SSL证书已成为网站安全的标配。但仅有SSL证书还不够,正确将其配置到服务器上,才能真正发挥保障数据传输安全、验证网站身份的作用。由于服务器类型多样,不同服务器的SSL证书配置方法存在差异&#xff0c…

AI与SEO关键词协同进化

内容概要 人工智能(AI)与搜索引擎优化(SEO)的结合,正深刻变革着关键词策略的制定与执行方式。本文旨在探讨AI技术如何驱动SEO关键词领域的智能化进化,核心在于利用AI强大的数据处理与模式识别能力&#xf…

01.线性代数是如何将复杂的数据结构转化为可计算的数学问题,这个过程是如何进行的

将复杂数据结构转化为可计算的数学问题是数据科学、机器学习和算法设计中的核心环节。这一过程需要结合数据特性、数学理论和计算框架,通过系统化的抽象和建模实现。以下是具体转化流程及关键技术解析: 一、数据结构分析:解构原始数据的本质特征 1. 识别数据类型与结构特性…

华为OD机考-网上商城优惠活动-模拟(JAVA 2025B卷)

import java.util.Scanner;public class Test3 {static int mjq;static int dzq;static int wmkq;static class Group {int price;// 打折后价格int num;// 优惠券使用熟练}public static void main(String[] args) {Scanner scanner new Scanner(System.in);String input sc…

JavaScript 数据处理 - 将字符串按指定位数截断并放入数组(基础实现、使用正则表达式实现、使用正则表达式简化实现)

将字符串按指定位数截断并放入数组 1、基础实现 /*** 将字符串按指定位数截断并放入数组* param {string} str - 要处理的字符串* param {number} n - 每段截断的位数* returns {Array} 截断后的字符串数组*/ function splitStringByLength(str, n) {const result [];for (l…

python学智能算法(十四)|机器学习朴素贝叶斯方法进阶-CountVectorizer文本处理简单测试

【1】引用 前序学习文章中,已经对拉普拉斯平滑和简单二元分类进行了初步探索,相关文章链接为: python学智能算法(十二)|机器学习朴素贝叶斯方法初步-拉普拉斯平滑计算条件概率-CSDN博客 python学智能算法&#xff0…

Java枚举类的规范设计与常见错误规避

前言 在Java开发中,枚举(enum)是一种强大的工具,用于定义一组固定常量集合。然而,许多开发者在使用枚举时容易陷入设计误区,导致代码可维护性差、运行时错误频发,甚至引发生产事故。 一、枚举…

Vue指令v-if

目录 一、Vue中的v-if指令是什么?二、v-if指令的使用 一、Vue中的v-if指令是什么? v-if指令是根据表达值的真假,切换元素的显示和隐藏, 本质是通过操纵dom元素来切换显示状态。 注意: 表达式的值为true,元…

探秘阿里云云数据库Tair:性能、特性与应用全景解析

引言 在数字化浪潮席卷全球的当下,数据已然成为企业最为关键的资产之一,如何高效管理和运用这些数据,成为了企业在激烈竞争中脱颖而出的关键。云数据库作为现代数据管理的核心工具,凭借其卓越的可扩展性、灵活性以及高效的数据处…