什么是代理模式,用 Python 如何实现 Proxy(代理 或 Surrogate)对象结构型模式?

news2024/10/7 8:24:58
什么是代理模式?

代理(Proxy)是一种结构型设计模式,其目的是通过引入一个代理对象来控制对另一个对象的访问。代理对象充当目标对象的接口,这样客户端就可以通过代理对象间接地访问目标对象,从而在访问过程中实现一些额外的控制、功能或处理。

在这里插入图片描述


代理模式主要有三种类型:保护代理、虚拟代理和远程代理。

  1. 保护代理(Protection Proxy): 控制对真实对象的访问权限,允许或拒绝对真实对象的请求。例如,访问控制、身份验证等功能可以通过保护代理来实现。
+-----------------+       +---------------------+       +----------------+
|   Subject       |       |    RealSubject     |       |     Proxy      |
|   +request()    |<------|   +SensitiveOp()   |<------| +request()     |
+-----------------+       +---------------------+       +----------------+

这个简单的图示表达了保护代理的基本结构。在保护代理中,代理对象可以在调用真实主题的方法前后添加一些控制逻辑,例如检查权限,确保敏感操作只有在合适的条件下才能被执行。

  1. 虚拟代理(Virtual Proxy): 控制对目标对象的访问,延迟目标对象的创建或加载,以减少系统开销。例如,加载大型图像或复杂对象时,可以使用虚拟代理进行懒加载,只有在需要时才真正创建目标对象。
+-----------------+       +---------------------+       +----------------+
|   Subject       |       |    RealSubject     |       |     Proxy      |
|   +request()    |<------|   +loadImage()      |<------| +request()     |
+-----------------+       +---------------------+       +----------------+

在虚拟代理(Virtual Proxy)中,“虚拟”体现在代理对象不立即创建或加载真实对象,而是在需要的时候才进行。这种延迟加载的行为使得代理对象在不实际创建真实对象的情况下提供相同的接口。因此,"虚拟"表示的是代理对象对真实对象的懒加载特性。

  1. 远程代理(Remote Proxy): 在不同地址空间中代理对象,使得可以在不同的系统中进行远程通信。远程代理允许客户端访问位于远程服务器上的对象,而不必了解底层的网络细节。
+-----------------+       +---------------------+       +----------------+
|   Subject       |       |    RealSubject     |       |     Proxy      |
|   +request()    |<------|   +remoteRequest() |<------| +request()     |
+-----------------+       +---------------------+       +----------------+

在远程代理中,代理对象充当了客户端和真实对象之间的中介,使得客户端可以透明地访问位于远程服务器上的真实对象。代理负责处理网络通信、序列化和反序列化等远程调用的细节,使得客户端无需了解底层的网络细节,实现了对远程对象的透明访问。


代理模式的主要优势包括:

  • 控制访问: 代理对象可以控制客户端对目标对象的访问,从而增强安全性或实现访问控制。

  • 延迟加载: 使用虚拟代理可以延迟目标对象的创建,减少系统启动时间和资源占用。

  • 简化接口: 代理对象可以提供更简单的接口,隐藏目标对象的复杂性。

  • 远程访问: 远程代理使得客户端可以访问远程服务器上的对象,实现分布式系统中的远程通信。


代理模式的一般结构包括:

  • 抽象主题(Subject): 定义了代理和真实对象的共同接口,客户端通过该接口访问真实对象。

  • 真实主题(Real Subject): 实现了抽象主题接口,是代理所代表的真实对象。

  • 代理(Proxy): 实现了抽象主题接口,保存了对真实对象的引用,可以在客户端访问真实对象前后执行一些额外的操作。

代理模式的实现方式在不同编程语言中可能有所不同,但核心思想是引入一个中间层(代理对象)来控制对目标对象的访问。这样的设计提供了更好的灵活性和可维护性,允许在不修改客户端代码的情况下改变目标对象的行为或实现。

模式的意图

为其他对象提供一种代理以控制对这个对象的访问。

别名

Surrogate


在 Python 3 中,如何实现(Proxy)代理设计模式

在 Python 中实现代理(Proxy)设计模式相对简单,因为 Python 语言的特性和语法支持可以轻松地创建代理对象。下面是一个简单的例子,演示了如何实现保护代理(Protection Proxy):

# 抽象主题(Subject)
class Subject:
    def request(self):
        pass

# 真实主题(Real Subject)
class RealSubject(Subject):
    def request(self):
        print("RealSubject: Handling request")

# 代理(Proxy)
class Proxy(Subject):
    def __init__(self, real_subject):
        self._real_subject = real_subject

    def request(self):
        # 添加额外的控制逻辑
        print("Proxy: Checking access permissions.")
        if self._check_access():
            # 调用真实主题的方法
            self._real_subject.request()
            print("Proxy: Logging the request.")
        else:
            print("Proxy: Access denied.")

    def _check_access(self):
        # 模拟访问权限控制
        # 在实际应用中,这里可能会涉及更复杂的逻辑,如身份验证等
        return True  # 允许访问

# 客户端代码
if __name__ == "__main__":
    real_subject = RealSubject()
    proxy = Proxy(real_subject)

    # 通过代理访问真实主题
    proxy.request()

在这个例子中:

  • Subject 是抽象主题,定义了代理和真实主题的共同接口。
  • RealSubject 是真实主题,实现了抽象主题的接口,表示真实的对象。
  • Proxy 是代理,包含一个对真实主题的引用,并在调用真实主题的方法前后添加了额外的控制逻辑。

在客户端代码中,我们首先创建了真实主题 RealSubject 和代理 Proxy 的实例,然后通过代理对象调用 request() 方法。代理对象会在调用真实主题的方法前后执行一些额外的操作,例如检查访问权限和记录请求。

这只是代理模式的一个简单示例,实际应用中可能涉及更复杂的场景和逻辑。代理模式可以根据具体的需求进行不同形式的实现,例如虚拟代理(Virtual Proxy)或远程代理(Remote Proxy)。


在实现代理模式时,有一些需要注意的地方:

  1. 接口一致性: 代理对象应该实现与真实对象相同的接口,以确保客户端能够无缝地切换代理和真实对象。

  2. 代理生命周期: 考虑代理对象和真实对象的生命周期。确保代理对象和真实对象的创建、销毁和状态管理都得到正确处理。

  3. 懒加载: 在虚拟代理中,确保真实对象的懒加载(延迟加载)逻辑正确实现,只有在需要时才真正创建或加载真实对象。

  4. 权限控制: 在保护代理中,确保代理对象正确地进行访问权限的控制,只有在符合条件时才允许客户端访问真实对象。

  5. 网络通信: 在远程代理中,要注意网络通信的问题,如处理超时、错误处理、序列化和反序列化等。

  6. 性能考虑: 使用代理模式可能引入一些性能开销,特别是在远程代理中。要仔细考虑性能需求,避免不必要的开销。

  7. 线程安全性: 如果在多线程环境中使用代理模式,确保代理对象的线程安全性,以避免潜在的并发问题。

  8. 代理组合: 考虑使用多个代理对象的组合,形成代理链。代理链可以实现更复杂的控制逻辑,但要注意确保每个代理的职责清晰且不重叠。

  9. 避免过度设计: 不要过度设计代理模式。根据实际需求,只添加必要的代理,以避免引入不必要的复杂性。

  10. 异常处理: 考虑代理对象和真实对象的异常处理。确保代理对象能够适当地处理异常,并在必要时传递给客户端。

总体来说,代理模式的实现需要根据具体场景灵活运用,确保代理对象能够正确地完成预期的功能,并且与真实对象协同工作。在设计和实现时,理清代理对象和真实对象的职责和关系是非常重要的。


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

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

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

相关文章

MyBatis 反射工具箱:带你领略不一样的反射设计思路

反射是 Java 世界中非常强大、非常灵活的一种机制。在面向对象的 Java 语言中&#xff0c;我们只能按照 public、private 等关键字的规范去访问一个 Java 对象的属性和方法&#xff0c;但反射机制可以让我们在运行时拿到任何 Java 对象的属性或方法。 有人说反射打破了类的封装…

基于php+thinkphp的网上书店购物商城系统

运行环境 开发语言&#xff1a;PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 系统主要分为管理员和用户二部分&#xff0c;管理员主要功能包括&#xff1a;首页、个人中心、用户管理、图书分类…

第28章_mysql缓存策略

文章目录 MySQL缓存方案目的分析缓存层作用举例 缓存方案选择场景分析 提升MySQL访问性能的方式MySQL主从复制读写分离连接池异步连接 缓存方案缓存和MySQL一致性状态分析制定读写策略 同步方案canalgo-mysql-transfer 缓存方案的故障问题及解决缓存穿透缓存击穿缓存雪崩缓存方…

基于Python+Django的寻人失物失物招领系统

运行环境 开发语言&#xff1a;Python python框架&#xff1a;django 软件版本&#xff1a;python3.7 数据库&#xff1a;mysql 5.7 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;PyCharm/vscode 前端框架:vue.js 项目介绍 寻人失物失物招领系统交流平台的主要使用…

【chatglm3】(3):在AutoDL上,使用4090显卡,部署ChatGLM3API服务,并微调AdvertiseGen数据集,完成微调并测试成功!附视频演示。

在AutoDL上&#xff0c;使用4090显卡&#xff0c;部署ChatGLM3API服务&#xff0c;并微调AdvertiseGen数据集&#xff0c;完成微调并测试成功&#xff01; 其他chatgpt 和chatglm3 资料&#xff1a; https://blog.csdn.net/freewebsys/category_12270092.html 视频地址&#…

傅里叶分析(2)

在《傅里叶分析&#xff08;1&#xff09;》中&#xff0c;讲述了连续信号的傅里叶分析方法&#xff0c;本文讲述离散信号的傅里叶分析方法。 虽然电、声、光、机械振动等信号在物理上是连续函数&#xff0c;但在实际工程中&#xff0c;其通常为离散信号&#xff0c;即若干离散…

Go的优雅退出

Go优雅退出/停机以前主要通过signal来实现&#xff0c;当然现在也是通过signal来实现&#xff0c;只是从go 1.16开始&#xff0c;新增了更加友好的API: func NotifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) 该…

2017年计网408

第33题 假设 OSI 参考模型的应用层欲发送 400B 的数据 (无拆分), 除物理层和应用层之外, 其他各层在封装 PDU 时均引入 20 B 的额外开销, 则应用层数据传输效率约为( )A. 80%B. 83%C. 87%D. 91% 本题考察有关数据包逐层封装的相关概念。我们来一起分析一下。 这是要求大家必须…

国际化:i18n

什么是国际化&#xff1f; 国际化也称作i18n&#xff0c;其来源是英文单词 internationalization的首末字符和n&#xff0c;18为中间的字符数。由于软件发行可能面向多个国家&#xff0c;对于不同国家的用户&#xff0c;软件显示不同语言的过程就是国际化。通常来讲&#xff0…

gradle 使用记录

gradle 使用记录 下载与设置android studio 配置 参考 IDEA如何配置 Gradle 及 Gradle 安装过程&#xff08;详细版&#xff09; 设置Gradle国内镜像并配置本地仓库地址 下载与设置 腾讯镜像下载 比如gradle-8.4-bin.zip 新建环境变量 GRADLE_HOME 为 D:\java\gradle &#…

基于springboot+vue健身管理系统

基于springbootvue健身管理系统 摘要 健身管理系统是一款基于Spring Boot和Vue.js的全栈应用&#xff0c;致力于为用户提供全面、个性化的健身管理体验。通过Spring Boot构建的后端&#xff0c;系统提供了强大的RESTful API支持&#xff0c;包括用户管理、健身计划制定和健康数…

Python数据容器之[列表]

Python数据容器 Python中的数据容器&#xff1a; 一种可以容纳多份数据的数据类型&#xff0c;容纳的每一份数据称之为1个元素 每一个元素&#xff0c;可以是任意类型的数据&#xff0c;如字符串、数字、布尔等。 数据容器根据特点的不同&#xff0c;如&#xff1a; 是否支…

IDEA 2023搭建 SpringMVC +FreeMarker+JDBC

1.IDEA的版本&#xff0c;目前最新是2023&#xff0c;要选择旗舰版。笔者曾选择社区版&#xff0c;发现少了很多功能。只能重新安装。 2.安装好以后的第1件事&#xff0c;是设置Maven&#xff0c;并将下载地址改为淘定站&#xff0c;参照这篇一次包会——最新IDEA配置Maven指南…

Java 算法篇-深入了解单链表的反转(实现:用 5 种方式来具体实现)

&#x1f525;博客主页&#xff1a; 小扳_-CSDN博客 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 单链表的反转说明 2.0 单链表的创建 3.0 实现单链表反转的五种方法 3.1 实现单链表反转 - 循环复制&#xff08;迭代法&#xff09; 3.2 实现单链表反转 - 头插法 3…

飞书开发学习笔记(五)-Python快速开发网页应用

飞书开发学习笔记(五)-Python快速开发网页应用 一.下载示例代码 首先进入飞书开放平台: https://open.feishu.cn/app 凭证与基础信息 页面&#xff0c;在 应用凭证 中获取 App ID 和 App Secret 值。 教程和示例代码位置:https://open.feishu.cn/document/home/integrating-…

YOLOv5算法进阶改进(2)— 引入可变形卷积模块 | 涨点杀器

前言:Hello大家好,我是小哥谈。可变形卷积模块是一种改进的卷积操作,它可以更好地适应物体的形状和尺寸,提高模型的鲁棒性。可变形卷积模块的实现方式是在标准卷积操作中增加一个偏移量offset,使卷积核能够在训练过程中扩展到更大的范围,从而实现对尺度、长宽比和旋转等各…

Linux_磁盘管理_df命令

1、df命令是用来干什么的 df的全称是disk free&#xff0c;意为“磁盘空间”。 使用df命令可以查看系统中磁盘的占用情况&#xff0c;有哪些文件系统&#xff0c;在什么位置&#xff08;挂载点&#xff09;&#xff0c;总空间&#xff0c;已使用空间&#xff0c;剩余空间等。…

2023.11.13【读书笔记】丨生物信息学与功能基因组学(第六章 多重序列比对 下)

目录 6.4 多重序列比对数据库6.5 基因组区域的多重序列比对6.6 展望6.7 常见问题总结 6.4 多重序列比对数据库 Pfam&#xff1a;基于谱隐马尔可夫模型构建的蛋白质家族数据库 SMART&#xff1a;简易分子构型研究工具&#xff0c;与细胞信号传导、细胞外结构域以及染色质功能…

Jmeter+ant+Jenkins持续集成

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

【C++入门篇】保姆级教程篇【下】

目录 一、运算符重载 1&#xff09;比较、赋值运算符重载 2&#xff09; 流插入留提取运算符重载 二、剩下的默认成员函数 1&#xff09;赋值运算符重载 2&#xff09;const成员函数 3&#xff09;取地址及const取地址操作符重载 三、再谈构造函数 1&#xff09;初始化列表 …