设计模式Python版 适配器模式

文章目录

  • 前言
  • 一、适配器模式
  • 二、适配器模式实现
  • 三、适配器模式在Django中的应用


前言

GOF设计模式分三大类:

  • 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
  • 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
  • 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。

一、适配器模式

适配器模式(Adapter Pattern)

  • 定义:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器的实现就是把客户类的请求转化为对适配者的相应接口的调用。

  • 解决问题:如何在不修改现有系统的前提下重用没有源码的第三方类库?

  • 使用场景:

    • 适配器模式通常用于现有系统与第三方产品功能的集成,采用增加适配器的方式将第三方类集成到系统中。
    • 当你希望使用一个已经存在的类,但其接口(例如方法名)不符合你的需求时。
    • 当你想要创建一个可重用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
    • 当你需要使用多个现有的子类,但又不想派生所有这些子类的适配器时,可以采用对象适配器,从而可以复用现有的子类。
  • 组成:

    • 目标(Target)接口/类:当前系统期望使用的接口,它定义了客户希望使用的方法。
    • 适配器(Adapter)类:一个中介类,它实现了目标接口,并通过私有方式包含一个被适配者的实例,从而将目标接口和被适配者接口匹配起来。
    • (被)适配者(Adaptee)类:一个现存的需要适配的类,它包含一些功能,但是不符合目标接口。
  • 优点:

    • 将目标类和适配者类解耦。通过引入一个适配器类来重用现有的适配者类,无须修改原有结构。
    • 增加了类的透明性和复用性。将具体的业务实现过程封装在适配者类中,对于客户端类而言是透明的,而且提高了适配者类的复用性,同一个适配者类可以在多个不同的系统中复用。

二、适配器模式实现

实现方法一:对象适配器模式

  • 在对象适配器模式(使用频率更高)中,适配器与适配者之间是关联关系

  • 对象适配器模式结构图

在这里插入图片描述

对象适配器模式示例

使用适配器模式来重用算法库中的QuickSort和BinarySearch算法

# 模块adapters.py
"""目标"""


class ScoreOperation:
    """抽象成绩操作类:目标接口"""

    def sort(self, scores: list[int]) -> list[int]:
        raise NotImplementedError

    def search(self, scores: list[int], key: int) -> int:
        raise NotImplementedError


"""适配器"""


class OperationAdapter(ScoreOperation):
    def __init__(self):
        self.sort_obj = QuickSort()  # 被适配者对象
        self.search_obj = BinarySearch()  # 被适配者对象

    def sort(self, scores):
        return self.sort_obj.quick_sort(scores)  # 调用被适配者方法

    def search(self, scores, key):
        return self.search_obj.binary_search(scores, key)  # 调用被适配者方法


"""被适配者"""


class QuickSort:
    def quick_sort(self, data: list[int]):
        # 快速排序算法(略)
        return sorted(data)


class BinarySearch:
    def binary_search(self, data: list[int], key: int):
        # 二分查找算法(略)
        return data.index(key) if key in data else None

引入配置文件config.json

{
    "class_name": "OperationAdapter"
}

工具类JsonUtil

# 模块 utils.py
from pathlib import Path
import json


class JsonUtil:
    @staticmethod
    def get_class_name():
        """读取配置文件,返回配置文件中的配置"""
        path = Path("config.json")
        contents = path.read_text(encoding="utf-8")
        conf = json.loads(contents)
        return conf.get("class_name", None)

客户端代码

  • 通过引入配置文件和反射机制,可以在不修改客户端代码的情况下使用新的适配器,无须修改源代码,符合开闭原则。
import adapters
from utils import JsonUtil

class_name = JsonUtil.get_class_name()
klass = getattr(adapters, class_name, None)
if klass is None:
    raise ValueError

operation: adapters.ScoreOperation = klass()
scores = [92, 98, 91, 100, 85, 80]
result = operation.sort(scores)
print(f"成绩排序结果:{result}")

print("查找成绩90:", end="")
if operation.search(result, 90):
    print("找到成绩90。")
else:
    print("没有找到成绩90。")

print("查找成绩92:", end="")
if operation.search(result, 92):
    print("找到成绩92。")
else:
    print("没有找到成绩92。")

输出结果

成绩排序结果:[80, 85, 91, 92, 98, 100]
查找成绩90:没有找到成绩90。
查找成绩92:找到成绩92。

实现方式二:类适配器模式

  • 在类适配器模式中,适配器与适配者之间是继承(或实现) 关系
  • 类适配器模式结构图

在这里插入图片描述

实现方式三:双向适配器模式

  • 在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。
  • 双向适配器模式结构图

在这里插入图片描述

三、适配器模式在Django中的应用

Django缓存框架设计理念:缓存 API 应该为不同的缓存后端提供一致的接口。Django 提供了多种缓存后端的支持,如本地内存、文件、数据库、Memcached 或 Redis 等。为了能够使用不同的缓存后端,Django 实现了缓存适配器,这些适配器为不同的缓存系统提供了统一的接口。

# 底层缓存API示例
from django.core.cache import cache

# cache.set(key, value, timeout=DEFAULT_TIMEOUT, version=None)
cache.set('my_key', 'hello, world!', 30)

# cache.get(key, default=None, version=None)
cache.get('my_key')

参考资料:Django缓存框架


您正在阅读的是《设计模式Python版》专栏!关注不迷路~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

科研绘图系列:R语言绘制散点图(scatter plot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据画图保存图片系统信息参考介绍 科研绘图系列:R语言绘制散点图(scatter plot) 加载R包 library(tidyverse) library(ggthemes) library(ggpubr) libr…

基于单片机的超声波液位检测系统(论文+源码)

1总体设计 本课题为基于单片机的超声波液位检测系统的设计,系统的结构框图如图2.1所示。其中包括了按键模块,温度检测模块,超声波液位检测模块,显示模块,蜂鸣器等器件设备。其中,采用STC89C52单片机作为主控…

P1044 [NOIP2003 普及组] 栈 C语言

P1044 [NOIP2003 普及组] 栈 - 洛谷 | 计算机科学教育新生态 题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。 栈有两种最重要的操作,即 pop(从栈顶弹出一个元素)和 pus…

基础项目实战——学生管理系统(c++)

目录 前言一、功能菜单界面二、类与结构体的实现三、录入学生信息四、删除学生信息五、更改学生信息六、查找学生信息七、统计学生人数八、保存学生信息九、读取学生信息十、打印所有学生信息十一、退出系统十二、文件拆分结语 前言 这一期我们来一起学习我们在大学做过的课程…

OpenEuler学习笔记(十七):OpenEuler搭建Redis高可用生产环境

在OpenEuler上搭建Redis高可用生产环境,通常可以采用Redis Sentinel或Redis Cluster两种方式,以下分别介绍两种方式的搭建步骤: 基于Redis Sentinel的高可用环境搭建 安装Redis 配置软件源:可以使用OpenEuler的默认软件源&#…

Python的那些事第六篇:从定义到应用,Python函数的奥秘

新月人物传记:人物传记之新月篇-CSDN博客 目录 一、函数的定义与调用 二、函数的参数 三、返回值(return语句) 四、作用域 五、匿名函数(lambda表达式) 六、总结 Python函数的奥秘:从定义到应用 编程…

vue3的路由配置

先找到Layout布局文件&#xff0c;从中找到左侧边栏&#xff0c;找到下述代码 <SidebarItem v-for"route in noHiddenRoutes" :key"route.path" :item"route" :base-path"route.path" />/** *菜单项 <SidebarItem>: *使用…

VLLM性能调优

1. 抢占 显存不够的时候&#xff0c;某些request会被抢占。其KV cache被清除&#xff0c;腾退给其他request&#xff0c;下次调度到它&#xff0c;重新计算KV cache。 报这条消息&#xff0c;说明已被抢占&#xff1a; WARNING 05-09 00:49:33 scheduler.py:1057 Sequence gr…

Blazor-@bind

数据绑定 带有 value属性的标记都可以使用bind 绑定&#xff0c;<div>、<span>等非输入标记&#xff0c;无法使用bind 指令的&#xff0c;默认绑定了 onchange 事件&#xff0c;onchange 事件是指在输入框中输入内容之后&#xff0c;当失去焦点时执行。 page &qu…

H264原始码流格式分析

1.H264码流结构组成 H.264裸码流&#xff08;Raw Bitstream&#xff09;数据主要由一系列的NALU&#xff08;网络抽象层单元&#xff09;组成。每个NALU包含一个NAL头和一个RBSP&#xff08;原始字节序列载荷&#xff09;。 1.1 H.264码流层次 H.264码流的结构可以分为两个层…

Qt中QVariant的使用

1.使用QVariant实现不同类型数据的相加 方法&#xff1a;通过type函数返回数值的类型&#xff0c;然后通过setValue来构造一个QVariant类型的返回值。 函数&#xff1a; QVariant mainPage::dataPlus(QVariant a, QVariant b) {QVariant ret;if ((a.type() QVariant::Int) &a…

C++,STL 简介:历史、组成、优势

文章目录 引言一、STL 的历史STL 的核心组成三、STL 的核心优势四、结语进一步学习资源&#xff1a; 引言 C 是一门强大且灵活的编程语言&#xff0c;但其真正的魅力之一在于其标准库——尤其是标准模板库&#xff08;Standard Template Library, STL&#xff09;。STL 提供了…

每日一题——序列化二叉树

序列化二叉树 BM39 序列化二叉树题目描述序列化反序列化 示例示例1示例2 解题思路序列化过程反序列化过程 代码实现代码说明复杂度分析总结 BM39 序列化二叉树 题目描述 请实现两个函数&#xff0c;分别用来序列化和反序列化二叉树。二叉树的序列化是将二叉树按照某种遍历方式…

关于安卓greendao打包时报错问题修复

背景 项目在使用greendao的时候&#xff0c;debug安装没有问题&#xff0c;一到打包签名就报了。 环境 win10 jdk17 gradle8 项目依赖情况 博主的greendao是一个独立的module项目&#xff0c;项目目前只适配了java&#xff0c;不支持Kotlin。然后被外部集成。greendao版本…

Java实现.env文件读取敏感数据

文章目录 1.common-env-starter模块1.目录结构2.DotenvEnvironmentPostProcessor.java 在${xxx}解析之前执行&#xff0c;提前读取配置3.EnvProperties.java 这里的path只是为了代码提示4.EnvAutoConfiguration.java Env模块自动配置类5.spring.factories 自动配置和注册Enviro…

【AutoSar】汽车诊断标准协议UDS详解

目录 一、基本概念二、UDS诊断协议2.1 诊断服务的概念2.2常用的诊断服务2.2.1 诊断会话控制服务&#xff08;10服务&#xff09;2.2.2 会话访问0x27服务2.2.3 用于读写的DID的0x22/0x2E服务 一、基本概念 车辆的诊断需要有Tester端和ECU段通过应答的方式进行通信&#xff0c;他…

Java线程认识和Object的一些方法

本文目标&#xff1a; 要对Java线程有整体了解&#xff0c;深入认识到里面的一些方法和Object对象方法的区别。认识到Java对象的ObjectMonitor&#xff0c;这有助于后面的Synchronized和锁的认识。利用Synchronized wait/notify 完成一道经典的多线程题目&#xff1a;实现ABC…

【漫话机器学习系列】067.希腊字母(greek letters)-写法、名称、读法和常见用途

希腊字母&#xff08;Greek Letters&#xff09; 希腊字母在数学、科学、工程学和编程中广泛使用&#xff0c;常用于表示变量、常量、参数、角度等。以下是希腊字母的完整列表及其常见用途。 大写与小写希腊字母表 大写小写名称&#xff08;英文&#xff09;名称&#xff08;…

【Block总结】OutlookAttention注意力,捕捉细节和局部特征|即插即用

论文信息 标题: VOLO: Vision Outlooker for Visual Recognition作者: Li Yuan, Qibin Hou, Zihang Jiang, Jiashi Feng, Shuicheng Yan代码链接: https://github.com/sail-sg/volo论文链接: https://arxiv.org/pdf/2106.13112 创新点 前景注意力机制: VOLO引入了一种称为“…

Linux Samba 低版本漏洞(远程控制)复现与剖析

目录 前言 漏洞介绍 漏洞原理 产生条件 漏洞影响 防御措施 复现过程 结语 前言 在网络安全的复杂生态中&#xff0c;系统漏洞的探索与防范始终是保障数字世界安全稳定运行的关键所在。Linux Samba 作为一款在网络共享服务领域应用极为广泛的软件&#xff0c;其低版本中…