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

【设计模式】深入理解Python中的适配器模式(Adapter Pattern)

深入理解Python中的适配器模式(Adapter Pattern)

在软件开发中,常常会遇到需要让不兼容的类或接口协同工作的问题。适配器模式(Adapter Pattern)是一种结构型设计模式,通过提供一个包装器对象,将一个类的接口转换成客户端期望的另一种接口,从而解决类接口不兼容的问题。

本文将详细探讨适配器模式的定义、应用场景、实现步骤,以及如何在Python中实现该模式,并探讨其优缺点及扩展。

1. 什么是适配器模式?

适配器模式是一种结构型设计模式,它允许我们将一个类的接口转换成另一类的接口,使得原本由于接口不兼容而无法一起工作的类可以协同工作。适配器模式的核心思想是创建一个包装类,该类包装了现有的类,并通过包装的方式为客户端提供期望的接口。

适配器模式的角色

适配器模式主要包括以下几个角色:

  1. 目标接口(Target):客户端期望使用的接口或抽象类。
  2. 现有类(Adaptee):需要适配的现有类,它具有不兼容的接口。
  3. 适配器(Adapter):适配器类负责将 Adaptee 的接口转换成 Target 的接口,从而使得客户端能够通过 Target 接口使用 Adaptee 的功能。

UML 类图表示

+--------------------+     +-------------------+
|     Target         |     |     Adaptee        |
+--------------------+     +-------------------+
| +request()         |     | +specific_request()|
+--------------------+     +-------------------+▲                        ▲  |                        ||                        ||                        |
+--------------------+     +-------------------+
|     Adapter        |     | Client            |
+--------------------+     +-------------------+
| +request()         |     | +use_target()     |
| -adaptee: Adaptee  |     +-------------------+
+--------------------+

适配器模式的两种形式

  1. 对象适配器:通过组合的方式,适配器类包含一个被适配的类的实例。
  2. 类适配器:通过继承的方式,适配器类同时继承目标类和被适配类。

2. 适配器模式的应用场景

适配器模式适用于以下几种情况:

  1. 接口不兼容的类需要协同工作:当已有的类由于接口不兼容而无法直接与系统中的其他类协同工作时,适配器模式是理想的解决方案。
  2. 复用已有的类,而不改变其代码:当一个类的功能符合需求,但它的接口与现有的系统不兼容时,可以通过适配器模式进行复用,而不需要修改已有类的代码。
  3. 使用第三方库或API:如果一个外部库或API的接口不符合当前系统的需求,可以通过适配器将其封装为符合需求的接口。

实际应用场景

  • 数据库驱动适配:当使用不同数据库时,适配器模式可以将不同数据库驱动的API接口转换为统一的数据库访问接口。
  • 日志系统适配:当需要将不同的日志系统统一到一个接口时,可以通过适配器模式来适配不同的日志库。
  • UI适配器:在跨平台UI开发中,不同平台的UI组件接口可能不同,适配器模式可以帮助封装不同的UI组件以提供统一的接口。

3. Python 实现适配器模式

接下来,我们将通过代码来演示如何在Python中实现适配器模式。我们会以一个例子展开:假设我们有一个 Adaptee 类,它具有一个不符合当前系统需求的方法 specific_request,我们需要通过适配器将它适配成 Target 类中的 request 方法。

3.1 对象适配器的实现

对象适配器通过组合的方式来适配不兼容的类。

定义现有类(Adaptee)
class Adaptee:def specific_request(self):return "Adaptee: Specific behavior"
定义目标接口(Target)
class Target:def request(self):pass
定义适配器类(Adapter)

适配器类将 Adapteespecific_request() 方法转换为 Targetrequest() 方法。

class Adapter(Target):def __init__(self, adaptee: Adaptee):self.adaptee = adapteedef request(self):return f"Adapter: Translated {self.adaptee.specific_request()}"
客户端代码

客户端可以通过 Target 接口使用 Adaptee 的功能,而不需要直接访问 Adaptee 类。

def client_code(target: Target):print(target.request())# 使用适配器
adaptee = Adaptee()
adapter = Adapter(adaptee)
client_code(adapter)

输出:

Adapter: Translated Adaptee: Specific behavior

在这个例子中,客户端只需要使用 Target 接口,而适配器 AdapterAdaptee 的接口转换为客户端期望的接口。

3.2 类适配器的实现

类适配器通过继承的方式适配 Adaptee 类和 Target 类。Python支持多重继承,因此我们可以通过继承 AdapteeTarget 来实现类适配器。

class ClassAdapter(Target, Adaptee):def request(self):return f"ClassAdapter: Translated {self.specific_request()}"# 使用类适配器
adapter = ClassAdapter()
client_code(adapter)

输出:

ClassAdapter: Translated Adaptee: Specific behavior

这种方式避免了组合的使用,适合在多重继承不会带来复杂性时使用。

4. 适配器模式的优缺点

优点

  1. 提高了类的复用性:适配器模式允许我们在不修改已有代码的情况下使用不兼容的类,从而提高代码的复用性。
  2. 遵循单一职责原则:通过适配器类处理接口的转换工作,使得每个类都专注于自身的职责。
  3. 提高了系统的灵活性:可以很容易地添加新的适配器来适配不同的类,使系统具有更高的可扩展性。

缺点

  1. 增加了系统的复杂性:使用适配器模式会增加额外的适配器类,这可能会使系统的结构更加复杂。
  2. 性能开销:适配器模式通过包装方式引入了一层额外的调用,会在一定程度上增加系统的性能开销,特别是在高频调用的场景中。

5. Python特性下的适配器模式改进

Python作为动态语言,提供了一些特性,可以简化适配器模式的实现,比如鸭子类型装饰器。通过这些特性,可以使适配器模式的实现更加灵活。

使用鸭子类型简化适配器

Python中的鸭子类型(Duck Typing)允许我们不严格依赖类型检查,只要对象具有相应的方法就可以直接调用。因此,适配器模式在Python中可以变得更加简洁。

class Adaptee:def specific_request(self):return "Adaptee: Specific behavior"class Client:def request(self, obj):return obj.specific_request()adaptee = Adaptee()
client = Client()
print(client.request(adaptee))

在这个例子中,Client 类并不关心传入的对象是什么类型,只要它具有 specific_request 方法即可。这是一种基于行为的动态适配,不需要额外的适配器类。

使用装饰器动态适配

装饰器是Python中一种非常强大的功能,可以用来动态修改或扩展对象的行为。在适配器模式中,装饰器可以用来动态适配对象。

def adapter_decorator(func):def wrapper():return f"Adapter Decorator: Translated {func()}"return wrapperclass Adaptee:def specific_request(self):return "Adaptee: Specific behavior"adaptee = Adaptee()
adaptee.specific_request = adapter_decorator(adaptee.specific_request)
print(adaptee.specific_request())

输出:

Adapter Decorator: Translated Adaptee: Specific behavior

通过使用装饰器,我们可以动态

适配对象的方法,而无需显式定义适配器类。

6. 结论

适配器模式是一个非常有用的设计模式,尤其在需要将不兼容的类或接口组合使用的场景中。通过适配器,系统可以在不修改已有代码的情况下重用类,从而提高灵活性和可扩展性。

在Python中,适配器模式的实现可以通过对象适配、类适配、鸭子类型和装饰器等方式进行,具体选择哪种方式取决于项目的需求和复杂性。

适配器模式虽然增加了系统的结构复杂度,但在实际应用中,它有效地提高了代码的复用性和系统的扩展能力。如果你在项目中遇到了接口不兼容的问题,适配器模式可能就是你需要的解决方案。

相关文章:

【设计模式】深入理解Python中的适配器模式(Adapter Pattern)

深入理解Python中的适配器模式(Adapter Pattern) 在软件开发中,常常会遇到需要让不兼容的类或接口协同工作的问题。适配器模式(Adapter Pattern)是一种结构型设计模式,通过提供一个包装器对象,…...

RuoYi-Vue若依框架-后端设置不登陆访问(白名单)

找到SecurityConfig类 确认自己的需求 /*** anyRequest | 匹配所有请求路径* access | SpringEl表达式结果为true时可以访问* anonymous | 匿名可以访问* denyAll | 用户不能访问* fullyAuthenticated | 用户完全认证可…...

C语言初阶小练习2(三子棋小游戏的实现代码)

这是C语言小游戏三子棋的代码实现 test.c文件是用来测试的部分 game.h文件是用来声明我们说写出的函数 game.c文件是用来编写我们的功能实现函数部分 1.test.c #define _CRT_SECURE_NO_WARNINGS 1 #include"game.h" void menu() {printf("***************…...

金融行业合同管理如何利用AI技术进行风险预警?

2024年以来,金融行业的发展主线被锚定,强调了防风险的基调,尤其是系统性风险的防范。金融工作的重点在于实现六个强大:强大的货币、强大的中央银行、强大的金融机构、强大的国际金融中心、强大的金融监管、强大的金融人才队伍。这…...

世界数字农业盛宴与技术探索,25年3月聚焦世界灌溉科技大会

由中国农业节水和农村供水技术协会、中国农垦节水农业产业技术联盟、北京物联网智能技术应用协会、振威国际会展集团主办的“世界灌溉科技大会”、“第11届北京国际数字农业与灌溉技术博览会”,定于2025年3月31日至4月2日在北京国家会议中心举办。 作为世界三大灌溉…...

二百六十九、Kettle——ClickHouse清洗ODS层原始数据增量导入到DWD层表中

一、目的 清洗ClickHouse的ODS层原始数据,增量导入到DWD层表中 二、实施步骤 2.1 newtime select( select create_time from hurys_jw.dwd_statistics order by create_time desc limit 1) as create_time 2.2 替换NULL值 2.3 clickhouse输入 2.4 字段选择 2.5 …...

Maya---骨骼绑定

调节骨骼大小 回车键确认骨骼 FK子集跟父集走 IK子集不跟父集走 前视图中按shift键添加骨骼 清零、删除历史记录,创建新的物体...

携手并进,智驭教育!和鲸科技与智谱 AI 签署“101 数智领航计划”战略合作协议

近日,上海和今信息科技有限公司(以下简称“和鲸科技”)与北京智谱华章科技有限公司(以下简称“智谱 AI”)签署“101 数智领航计划”战略合作协议。双方将携手营造智能化学科教育与科研环境,提供多种大模型工…...

牛客周赛63

https://ac.nowcoder.com/acm/contest/91592 好数 简单的判断两位数&#xff0c;且十位等于个位 #include <bits/stdc.h> #define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define int long long using namespace std; using ll long long; using pii …...

git restore恢复删除文件

新版本 在 Git 2.23 版本之后&#xff0c;Git 引入了一个新的命令 git restore&#xff0c;用于简化文件恢复操作。可以用 git restore 来恢复误删除的文件。下面是详细的使用方法&#xff1a; 1. 恢复工作区中删除的文件&#xff08;未提交&#xff09; 如果文件已被删除&a…...

MacOS13虚拟机VMware Workstation Pro 16安装

资源 安装unlocker 安装虚拟机 低版本的还没有MacOS13选项&#xff0c;这也是我安装低版本虚拟机踩过的坑 找个教程安装就可以了 省略…自己去找找教程… 过程中我使用桥接是不行的&#xff0c;没有网络&#xff0c;后面重新下一步一步的选择默认的网络重装后就好了&am…...

docker 数据管理,数据持久化详解 一

docker镜像是分层设计的&#xff0c;镜像出只读&#xff0c;通过镜像启动的容器添加一层可读写的文件系统&#xff0c;用户写入的数据表都保存在这层中。 容器的数据分层目录 LowerDir&#xff1a;image 镜像层&#xff0c;即镜像本身&#xff0c;制度 UpperDir&#xff1a;容…...

【ios】使用TestFlight将app分发给测试人员(超详细)

我的环境&#xff1a; macos系统是Ventura 13.0 xcode是14.2&#xff08;后面发现至少需要15版本的xcode才能上传app&#xff09; 证书生成 可以通过xcode生成Distribution类型的证书&#xff0c;如果你已经有的话那就忽略&#xff0c;这个证书也是备案时所需的。 我是已…...

证件照小程序源码,前后端稳定运行

演示&#xff1a;证寸照制作 运行环境: Linux Nginx PHP >5.6 MySQL>5.6 安装步骤: 1.下载源码上传至你的服务器宝塔面板 2.直接添加站点选择源码目录&#xff0c;新建数据库 3.设置代码执行目录为/web 4.在浏览器中输入你的域名&#xff0c;会提示安装&#xff0c;填写…...

java白嫖同事的从身份证里面提取省市区地址详细信息的工具类代码

/*** author sunpeiyang* date 2024/10/21 16:35*/ Slf4j public class MiTaAddressExtractor {/*** 获取详细地址** param fullAddress 身份证完整地址*/public static String getDetailedAddress(String fullAddress) {String[] addressArrays spliceDetailedAddress(fullAd…...

计算机网络基本架构示例2

一、企业内部网络架构 在一个中型企业中&#xff0c;通常会有以下的网络架构&#xff1a; - 核心层&#xff1a;由高性能的核心交换机组成&#xff0c;负责快速转发大量数据。例如采用具有高带宽和冗余功能的三层交换机&#xff0c;确保整个网络的稳定运行。它连接着各个部门的…...

无人机之室内定位技术篇

无人机的室内定位技术是实现无人机在室内环境中精准导航和定位的关键技术。由于室内环境复杂&#xff0c;卫星导航系统&#xff08;如GPS&#xff09;无法提供有效的信号&#xff0c;因此需要依赖其他室内定位技术。 一、主要技术类型 基于视觉的定位技术 原理&#xff1a;利…...

在ubuntu20.04中输入不存在shell命令时,报错ModuleNotFoundError的解决方案

这个问题出现过好几次&#xff0c;每次都比较困扰&#xff0c;以下的解决方案比较适合&#xff1a; 当我输入ubuntu无法识别的命令的时候&#xff0c;正常来说应该提示类似于 command not found 之类的字眼&#xff0c;但是系统确报了如下错误&#xff1a; Traceback (most r…...

互联网语言 互联网开发 互联网架构

JAVA和PHP是两种广泛应用于互联网开发的编程语言&#xff0c;它们在多个维度上展现出显著的不同。 JAVA是一种面向对象的编程语言&#xff0c;以其严谨、高效的特性而著称。JAVA的语法结构复杂且规范&#xff0c;强调封装、继承和多态等面向对象原则&#xff0c;适合构建大型企…...

解决MybatisPlus updateById更新数据时将没传的数据也更新成了null

首先&#xff0c;MybatisPlus在调用自带的更新接口updateById时&#xff0c;如果没加任何配置&#xff0c;默认是不会将前端没传的数据也更新成null的。即MyBatisPlus不会更新传入实体中为null的字段&#xff0c;只会更新设置了不为null的值。 如果发现没传的也更新成null了的话…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互

物理引擎&#xff08;Physics Engine&#xff09; 物理引擎 是一种通过计算机模拟物理规律&#xff08;如力学、碰撞、重力、流体动力学等&#xff09;的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互&#xff0c;广泛应用于 游戏开发、动画制作、虚…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)

文章目录 1.什么是Redis&#xff1f;2.为什么要使用redis作为mysql的缓存&#xff1f;3.什么是缓存雪崩、缓存穿透、缓存击穿&#xff1f;3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

Python爬虫(一):爬虫伪装

一、网站防爬机制概述 在当今互联网环境中&#xff0c;具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类&#xff1a; 身份验证机制&#xff1a;直接将未经授权的爬虫阻挡在外反爬技术体系&#xff1a;通过各种技术手段增加爬虫获取数据的难度…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...