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

设计模式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版》专栏!关注不迷路~


http://www.kler.cn/a/525785.html

相关文章:

  • Java 知识速记:全面解析 final 关键字
  • 数据结构 队列
  • 国产碳化硅(SiC)MOSFET模块在电镀电源中全面取代进口IGBT模块
  • Python练习(2)
  • 基于SpringBoot的假期周边游平台的设计与实现(源码+SQL脚本+LW+部署讲解等)
  • Java中的泛型
  • Vue.js 响应式引用与响应式数据(`ref` 和 `reactive`)
  • 【Python】深入探索Python元类:动态生成类与对象的艺术
  • 深入解析JPA中的多对多关系映射
  • Java---猜数字游戏
  • wordpress每隔24小时 随机推荐一个指定分类下的置顶内容。
  • 【Elasticsearch 】自定义分词器
  • Pyside6(PyQT5)的QSqlQueryModel的常用方法
  • 【C语言】main函数解析
  • 上位机知识篇---GitGitHub
  • 在MIMIC IV数据库的derived中有bg、chemistry和vitalsign,它们都有Glucose指标,如何区分?
  • C++并发编程指南06
  • 基于springboot的校园部门资料管理系统
  • 搜索引擎快速收录:关键词布局的艺术
  • DeepSeek回答人不会干出超出视角之外的事
  • 高速PCB设计指南4——叠层设计与PCB技术
  • 【CS61A 2024秋】Python入门课,全过程记录P4(Week7 Generators开始,更新于2025/1/30)
  • 使用langchain ollama gradio搭建一个本地基于deepseek r1的RAG问答系统
  • C28.【C++ Cont】顺序表的实现
  • 详细解释java当中的所有知识点(前言及数据类型及变量)(第一部分)
  • 《攻克语言密码:教AI理解隐喻与象征》