Python 如何实现适配器设计模式?什么是适配器(Adapter)设计模式?

news2024/11/24 12:05:30

什么是适配器设计模式?

适配器(Adapter)设计模式是一种结构型设计模式,它允许接口不兼容的类之间进行合作。适配器模式充当两个不兼容接口之间的桥梁,使得它们可以一起工作,而无需修改它们的源代码。

在这里插入图片描述

主要角色:

  1. 目标接口(Target): 定义客户端使用的接口,客户端通过该接口与适配器进行交互。

  2. 适配器(Adapter): 实现目标接口,并且持有一个被适配者的实例,将客户端的请求转换为被适配者能够处理的形式。

  3. 被适配者(Adaptee): 拥有一组不兼容目标接口的方法,适配器通过包装被适配者,使其能够与目标接口协同工作。

  4. 客户端(Client): 通过目标接口与适配器进行交互,无需直接与被适配者打交道。

工作流程:

  1. 客户端通过目标接口调用适配器的方法。

  2. 适配器内部持有一个被适配者的实例。

  3. 适配器将客户端的请求转换为被适配者能够理解的形式。

  4. 被适配者处理请求并返回结果。

  5. 适配器将结果转换为客户端期望的形式并返回。


Python 适配器设计模式示例代码(一):

假设有一个英语到法语的翻译器,但客户端只能接受英语接口,这时就需要适配器来转换法语接口为英语接口。

from abc import ABC, abstractmethod

# 目标接口
class EnglishSpeaker(ABC):
    @abstractmethod
    def speak_english(self):
        pass

# 被适配者
class FrenchSpeaker:
    def parler_francais(self):
        return "Je parle français"

# 适配器
class FrenchToEnglishAdapter(EnglishSpeaker):
    def __init__(self, french_speaker):
        self.french_speaker = french_speaker

    def speak_english(self):
        french_phrase = self.french_speaker.parler_francais()
        # 这里可以进行一些转换操作,这里简单地将法语短语翻译成英语
        english_translation = "I speak English: " + french_phrase
        return english_translation

# 客户端
def communicate_in_english(english_speaker):
    print(english_speaker.speak_english())

# 创建被适配者
french_speaker = FrenchSpeaker()

# 创建适配器
adapter = FrenchToEnglishAdapter(french_speaker)

# 客户端调用
communicate_in_english(adapter)

在这个示例中,EnglishSpeaker 是目标接口,FrenchSpeaker 是被适配者,FrenchToEnglishAdapter 是适配器。客户端通过目标接口与适配器交互,而适配器内部调用了被适配者的方法,将其转换为目标接口的形式。这使得客户端能够通过目标接口与被适配者进行通信。


Python3 适配器设计模式示例代码(二)

假设有一个系统,其中已经存在一个用于存储数据的类 Database,该类有一个名为 store_data 的方法。现在我们引入一个新的需求,需要将数据存储到云服务中,但云服务的接口与 Database 类的接口不同。我们可以使用适配器模式来使新的云服务类与现有的系统协同工作。

# 现有的数据库类
class Database:
    def store_data(self, data):
        print(f"Storing data in the local database: {data}")

# 云服务类(被适配者)
class CloudService:
    def upload(self, data):
        print(f"Uploading data to the cloud: {data}")

# 适配器
class CloudServiceAdapter(Database):
    def __init__(self, cloud_service):
        self.cloud_service = cloud_service

    def store_data(self, data):
        # 转换并调用云服务的接口
        cloud_data = self.convert_to_cloud_format(data)
        self.cloud_service.upload(cloud_data)

    def convert_to_cloud_format(self, data):
        # 在适配器中进行数据格式的转换
        return f"[Converted] {data}"

# 客户端代码
def save_data(database, data):
    database.store_data(data)

# 创建现有的数据库对象
local_database = Database()

# 客户端使用现有的数据库
save_data(local_database, "Some data")

# 创建云服务对象
cloud_service = CloudService()

# 创建适配器对象,使云服务与数据库接口兼容
cloud_service_adapter = CloudServiceAdapter(cloud_service)

# 客户端使用适配器,实际上调用了云服务的接口
save_data(cloud_service_adapter, "Data for the cloud")

在这个示例中,CloudService 类是被适配者,其接口与 Database 类不同。通过创建 CloudServiceAdapter 类,我们使得 CloudService 类能够适配到原有的系统中,客户端代码可以通过调用 store_data 方法来统一处理数据存储,而无需关心具体是本地数据库还是云服务。这种适配器模式的应用场景在实际开发中很常见,特别是在集成新的服务或组件时。


在实现适配器设计模式时,有哪些需要注意的地方?

在实现适配器设计模式时,有一些需要注意的地方,以确保模式的有效实施和系统的可维护性:

  1. 接口一致性: 确保适配器实现了目标接口,以便客户端可以一致地使用适配器和原始对象。

  2. 被适配者的接口: 确保理解被适配者的接口,了解如何将其转换为目标接口。这可能涉及到数据格式的转换、方法名称的改变等。

  3. 单一职责原则: 适配器通常需要处理两个不同接口之间的转换,但避免将太多的功能放入适配器,以确保每个类都遵循单一职责原则。

  4. 适配器类型: 适配器可以采用对象适配器或类适配器的形式。对象适配器使用组合,类适配器使用继承。选择适合你需求的适配器类型。

  5. 被适配者对象引入方式: 被适配者对象可以通过构造函数、初始化方法或其他方式引入。确保适配器能够持有被适配者对象的引用。

  6. 数据转换: 如果需要在适配器中进行数据格式的转换,确保转换是正确的,并且不会丢失关键信息。

  7. 异常处理: 考虑被适配者可能抛出的异常,确保适配器能够适当地处理这些异常或将其转换为适当的形式。

  8. 命名清晰: 适配器类的命名应当清晰地反映其用途,以便其他开发人员能够轻松理解和使用。

  9. 兼容性: 考虑被适配者和目标接口的未来变化,以确保适配器仍然能够正确工作。

  10. 测试: 编写充分的测试来验证适配器的正确性。测试应该覆盖适配器的所有行为,包括对不同接口的适应性。

  11. 文档: 提供清晰的文档,说明适配器的使用方式、目的和注意事项。这有助于其他开发人员更容易理解和使用适配器。

通过关注这些方面,可以确保适配器设计模式在系统中的有效应用。适配器模式通常用于集成新的组件、服务或库时,能够使不同接口的类能够协同工作。


本文就到这里了,感谢您的阅读 。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 🍇

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

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

相关文章

Hive入门--学习笔记

1,Apache Hive概述 定义: Hive是由Facebook开源用于解决海量结构化日志的数据统计,它是基于大数据生态圈Hadoop的一个数据仓库工具。 作用: Hive可以用于将结构化的数据文件【映射】为一张表,并提供类SQL查询功能。 H…

什么是原生IP与广播IP?如何区分?为什么需要用原生IP?

在代理IP中,我们常常听到原生IP与广播IP,二者有何区别?如何区分呢?下面为大家详细讲解。 一、什么是原生IP 原生IP地址是互联网服务提供商(ISP)直接分配给用户的真实IP地址,无需代理或转发。此…

OpenGL_Learn12(光照)

续OpenGL_Learn11(光照)-CSDN博客 1. 镜面高光 和漫反射光照一样,镜面光照也决定于光的方向向量和物体的法向量,但是它也决定于观察方向,例如玩家是从什么方向看向这个片段的。镜面光照决定于表面的反射特性。 我们通…

Redis:详解5大数据类型及其常用命令

目录 Redis键(key)字符串(String)简介常用命令数据结构简介常用命令 列表(List)简介常用命令数据结构 集合(Set)简介常用命令数据结构 哈希(Hash)简介常用命令…

Java排序算法之希尔排序

希尔排序(Shell Sort)又称“缩小增量排序”,是直接插入排序算法的一种更高效的改进版本。它的基本思想是:首先将整个数组按照一定的间隔分成若干个子序列,然后对每个子序列分别进行插入排序,减小间隔&#…

异步注解@Async失效的原因

在方法上加上Async注解,然后去启动类加上EnableAsync启动注解开启异步Async失效的原因 1、注解Async的方法不是public方法 2、注解Async的返回值只能为void或者Future 3、注解Async方法使用static修饰也会失效 4、spring无法扫描到异步类,没加注解Async …

AI大模型低成本快速定制法宝:RAG和向量数据库

文章目录 1. 前言2. RAG和向量数据库3. 论坛日程4. 购票方式 1. 前言 当今人工智能领域,最受关注的毋庸置疑是大模型。然而,高昂的训练成本、漫长的训练时间等都成为了制约大多数企业入局大模型的关键瓶颈。 这种背景下,向量数据库凭借其独特…

【yolov5报错解决】ModuleNotFoundError: No module named‘ultralytics.yolo‘

今天跑yolov5遇见一个报错,具体内容如下: 上面显示我没有ultralytics.yolo这个模块,但是我已经安装了ultralytics,同时,我也尝试了网上的方法pip install ultralytics.yolo,但是仍然得不到解决&#xff0c…

ai语音电销机器人电销行业要怎么降低封号率?

工信部对电话营销电话的管控越来越严格,企业电销行业的发展受到了很多限制,因为电话销售人员在进行销售工作的时候,经常会因为各种原因触发封号机制,导致手机卡号被封,那企业电销行业要怎么降低封号率? 很多…

图像格式导致halcon读取失败

图像格式: JPEG (jpg),文件头:FF D8 FF PNG (png),文件头:89 50 4E 47 GIF (gif),文件头:47 49 46 38 Windows Bitmap (bmp),文件头:42 4D 打开软件“notepad”使用16进…

win11无损关闭系统更新

1、窗口键R,打开运行窗口,输入regedit。 2、打开地址:计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 3、新建DWORD(32位)值(D),重命名“FlightSettingsMaxPauseDays” 4、…

正则匹配去除HTMl标签

正则匹配去除HTMl标签 案例&#xff1a;如在textarea中去除标签 操作方法 val.replace(/<[^>]>/g, ‘’))

基于SSM的校园停车场管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

Mysql执行报错:[Err] 1292 - Truncated incorrect DOUBLE value:***

MySQL执行语句抛出异常&#xff1a; 上面错误提示概是下面几种情况&#xff1a; 数据类型不匹配&#xff1a;在进行数值比较或运算时&#xff0c;数据类型可能不匹配。例如&#xff0c;将一个字符串值与一个 DOUBLE 类型的列进行比较或运算&#xff0c;或者将一个非数字字符串…

Qt QWebSocket实现JS调用C++

目录 前言1、QWebChannel如何与网页通信2、QWebSocketQWebChannel与网页通信2.1 WebSocketTransport2.2 WebSocketClientWrapper2.3 初始化WebSocket服务器2.4 前端网页代码修改 总结 前言 本篇主要介绍实现JS调用C的另一种方式&#xff0c;即QWebSocketQWebChannel。与之前的…

论文阅读:YOLOV: Making Still Image Object Detectors Great at Video Object Detection

发表时间&#xff1a;2023年3月5日 论文地址&#xff1a;https://arxiv.org/abs/2208.09686 项目地址&#xff1a;https://github.com/YuHengsss/YOLOV 视频物体检测&#xff08;VID&#xff09;具有挑战性&#xff0c;因为物体外观的高度变化以及一些帧的不同恶化。有利的信息…

韦东山linux驱动开发学习【常更】

1.linux目录简单介绍 2.直接运行需要在$path路径下

cmake简单使用

简介 理论上&#xff0c;任意一个C程序都可以用g来编译。 但当程序规模越来越大时&#xff0c;一个工程可能有许多个文件夹和源文件&#xff0c;这时输入的编译命令将越来越长。通常&#xff0c;一个小型C项目可能含有十几个类&#xff0c;各类间还存在着复杂的依赖关系。其中…

Unity优化(1)——合并Mesh

在某些移动端项目中&#xff0c;对于DrawCall的要求是很严格的&#xff0c;我们一般查看DrawCall可以通过Statistics里面的Batches进行查看&#xff0c;一般移动设备的Batches要控制在200左右比较合适&#xff0c;所以降低Batches是很重要的。 我们常常会遇到一个物体下挂载很多…

【观察】OpenHarmony:技术先进“创新局”,持续创新“谋新篇”

毫无疑问&#xff0c;开源作为今天整个软件产业的创新“原动力”&#xff0c;目前在软件产业发展中的重要性愈加凸显。根据Linux基金会的统计&#xff0c;现在全球软件产业中有70%以上的代码来源于开源软件。 从这个角度来看&#xff0c;开源技术已逐渐成为推动企业数字化转型和…