Python代理模式介绍、使用

一、Python代理模式介绍

        Python代理模式(Proxy Pattern)是一种结构型设计模式。在代理模式中,代理对象充当了另一个对象的占位符,以控制对该对象的访问。

代理对象和被代理对象实现了相同的接口,因此它们可以互相替代。客户端和代理对象之间的交互是无缝的,因为它们的接口是一样的。

代理模式的主要功能是为其他对象提供一个代理,以控制对对象的访问。代理对象可以在调用被代理对象之前或之后执行一些操作,例如身份验证,缓存等。

优点:

  • 保护了真实对象的访问,可以对访问进行限制和控制;
  • 可以提高访问效率,通过代理对象可以缓存数据或者调用其他服务等;
  • 可以提高系统的灵活性,因为代理对象可以在不影响真实对象的情况下扩展其功能。

缺点:

  •  可能引入额外的复杂性,因为需要创建代理对象。
  •  此外,如果代理对象没有正确实现与真实对象相同的接口,可能会导致客户端代码无法正常工作。

应用场景:

  • 身份验证:在访问某些敏感数据或操作时,可以使用代理对象执行身份验证,以确保用户有权访问该数据或执行该操作。
  • 缓存:使用代理对象来缓存数据,以便在下一次访问时可以更快地访问数据。
  • 远程服务:代理对象可以用作远程服务的本地代表,在使用远程服务时提供更好的用户体验,同时也可以提高访问效率。

代理模式可以通过组合或继承实现。通常,代理对象会继承与真实对象相同的接口,并在继承的方法中调用真实对象的方法。

二、代理模式使用

工作原理:

  • 客户端代码通过代理对象调用真实对象。
  • 代理对象执行一些额外的操作(例如身份验证或缓存),然后调用真实对象的方法。
  • 真实对象执行所请求的操作,并将结果返回给代理对象。
  • 代理对象将结果返回给客户端代码。

示例一:实现缓存功能

假设我们正在开发一个网络应用程序,该应用程序可以向外提供图片资源。由于图片资源较大,我们希望通过代理模式来缓存这些数据,以提高程序的性能和响应速度。

下面是一个基于Python的实现示例:


from abc import ABC, abstractmethod# 定义抽象基类
class Image():@abstractmethoddef display(self):pass# 定义具体子类,继承Image,重新display方法
class RealImage(Image):def __init__(self, filename): # 构造函数,接收一个参数filenameself.filename = filename  # 文件名保存在filename实例变量中self.load_from_disk()     # 调用load_from_disk()方法,从磁盘中加载图片数据'''从磁盘中加载图片数据子类RealImage独有的方法由于这个过程比较耗时,因此我们需要在初始化时进行加载,避免在图片显示时等待。'''def load_from_disk(self): #print("loading " + self.filename)# 显示图片def display(self):print("Displaying " + self.filename)# 定义代理类,继承Image,重写display方法
class ImageProxy(Image):def __init__(self, filename):self.filename = filename# 定义真实图片self.real_image = Nonedef display(self):if self.real_image is None:# 如果没有加载真实图片# 调用具体子类RealImage, 创建真实图片对象, 缓存真实对象,避免重复加载图片资源self.real_image = RealImage(self.filename)# 显示真实图片self.real_image.display()image = ImageProxy("test.jpg")
print("第一次调用display方法:图片没有加载真实图片,调用子类RealImage, 创建真实图片对象")
image.display()
print("第二次调用display方法: 直接从缓存中获取图片")
image.display()

运行结果: 

第一次调用display方法:图片没有加载真实图片,调用子类RealImage, 创建真实图片对象
loading test.jpg
Displaying test.jpg
第二次调用display方法: 直接从缓存中获取图片
Displaying test.jpg

在上面的示例中,我们定义了一个抽象基类Image,其中包含一个display()抽象方法。接着,我们定义了一个具体子类RealImage,它代表了真实的图片对象,负责从磁盘中加载图片数据,并提供display()方法用于显示图片。

我们还定义了一个代理类ImageProxy,它也实现了Image接口。当客户端调用display()方法时,代理类会检查是否已经加载了真实的图片对象。如果没有,代理会先创建一个真实的图片对象,然后再调用它的display()方法。这样,代理对象就可以缓存真实对象,避免了重复加载图片资源,从而提高程序性能。

使用代理模式时,客户端代码只需要与代理对象交互,并不需要知道真实对象的存在。当代理对象需要访问真实对象时,它会自动创建并调用真实对象,从而实现对真实对象的间接访问。

示例二:实现身份验证功能

在Python中,使用代理模式实现身份验证功能可以参考以下示例代码:

# 定义抽象主题类
class AbstractSubject():def request(self):pass# 定义子类真实主题对象,继承抽象主题类
class RealSubject(AbstractSubject):def request(self):print("RealSubject: 处理请求...")# 定义代理类, 继承抽象主题类
class Proxy(AbstractSubject):def __init__(self, realsubject: RealSubject, username: str, password: str):self._subject = realsubjectself._username = usernameself._password = passworddef request(self):if self.authenticdate():self._subject.request() # 调用子类request方法else:print("代理认证失败")def authenticdate(self):# 模拟身份认证过程if self._username == "admin" and self._password == "admin123456":print("代理认证成功")return Trueelse:return False# 创建真实主题对象
real_subject = RealSubject()# 创建代理对象
proxy = Proxy(real_subject, "admin", "admin123456")
# 通过代理对象发送请求
proxy.request()# 修改代理认证信息,再次发送请求
proxy._username = "a"
proxy._password = "b"
proxy.request()

运行结果:

代理认证成功
RealSubject: 处理请求...
代理认证失败

在上述示例代码中,我们定义了一个抽象主题类AbstractSubject和其子类RealSubject,并在代理类Proxy中持有一个真实主题对象_subject。在客户端调用时,通过代理对象proxy发送请求。

在代理类中,我们重写了request()方法,在其中添加了身份验证的逻辑。如果身份验证成功,则代理对象将请求转发给真实主题对象;否则,代理对象将输出代理认证失败的消息。

代理类Proxy的构造函数包含三个参数:

  • realsubject参数是真实主题对象,使用类型提示指定为RealSubject类。
  • username参数是用于身份认证的用户名,使用类型提示指定为字符串类型。
  • password参数是用于身份认证的密码,使用类型提示指定为字符串类型。

在代理类的构造函数中,将输入的真实主题对象、用户名和密码保存到对应的成员变量中,以便后续使用。

在客户端调用过程中,我们创建了一个真实主题对象real_subject和代理对象proxy,并通过代理对象发送请求。我们可以通过修改代理认证信息,测试代理类的身份验证功能是否正常工作。

示例三:实现远程服务功能

以下是一个示例代码,演示了如何使用 Python 代理模式实现远程服务功能:

from abc import ABC, abstractmethod# 定义抽象类:远程服务接口
class RemoteService():@abstractmethoddef request(self, param: str) -> str: # 抽象方法:接受字符串类型参数,返回字符串类型结果pass# 实现远程服务
class RemoteServiceIml(RemoteService):def request(self, param: str) -> str:return f"Remote service received {param}"# 实现代理类
class RemoteServiceProxy(RemoteService):def __init__(self, remote_service: RemoteService):self._remote_service = remote_servicedef request(self, param: str) -> str:print("Remote service aouthentication...")# 调用远程服务器前,本地操作...,例如:身份认证、参数校验if not param:raise ValueError("Missing parameter")# 调用远程服务,返回结果return self._remote_service.request(param)remote_service_impl = RemoteServiceIml()
proxy = RemoteServiceProxy(remote_service_impl)res = proxy.request("test")
print(res)

运行结果:

Remote service aouthentication...
Remote service received test

在上述代码中,我们首先定义了一个远程服务接口RemoteService,其中有一个request方法,用于处理远程服务请求,返回一个字符串类型的结果。同时,我们还实现了RemoteServiceImpl类,该类用于实现具体的远程服务逻辑。在具体的request方法中,简单地将接收到的参数拼接成一条消息,并返回。

接下来,我们使用代理模式实现了RemoteServiceProxy类,该类也实现了RemoteService接口,并接收一个RemoteService实例作为构造函数参数。当我们调用request方法时,代理类先进行身份认证、参数校验等本地操作,然后再调用远程服务,最后将结果返回。

在使用示例中,我们先创建了RemoteServiceImpl的实例,然后将它传入代理类的构造函数中创建代理对象proxy。最后,我们调用代理对象的request方法,传入一个字符串参数,并将返回结果打印出来。这个例子展示了代理模式如何在应对远程服务时起到的作用。

def request(self, param: str) -> str:解释:

这段代码是一个抽象方法的定义,其中request是一个接受一个字符串类型的参数,返回一个字符串类型的结果的抽象方法,但是该方法没有具体实现,只是提供了一个方法头。这种方法被称为抽象方法,是一种在抽象类中定义,需要在子类中具体实现的方法。在Python中,我们可以通过定义抽象类和使用abstractmethod装饰器来实现抽象方法的定义。子类必须实现抽象类中的所有抽象方法才能被实例化,并且子类中的抽象方法也可以再次定义为抽象方法,以继续在更深层次上实现多态行为。

raise ValueError("Missing parameter")解释:

这段代码是一个异常抛出语句,当代码执行到此处时,会抛出一个ValueError类型的异常,并传递一个字符串参数"Missing parameter"作为异常信息。异常机制是Python中的一种错误处理机制,当程序出现错误时,可以使用异常机制提前中止程序的运行,并在异常发生的地方引发一个异常对象,这样就可以将错误信息传递给上层调用的代码,以便于更好地处理错误。在Python中,可以使用raise语句抛出一个异常对象,从而使得程序进入异常处理流程。

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

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

相关文章

类加载机制与类加载器

点击下方关注我,然后右上角点击...“设为星标”,就能第一时间收到更新推送啦~~~ Java 源码是如何形成类文件的,类文件又是如何加载到虚拟机的,类加载有哪些机制和原则呢?本文将为大家一一介绍。 1 Java 源码形成类文件…

基于拉格朗日-遗传算法的最优分布式能源DG选址与定容(Matlab代码实现)

目录 1 概述 2 数学模型 2.1 问题表述 2.2 DG的最佳位置和容量(解析法) 2.3 使用 GA 进行最佳功率因数确定和 DG 分配 3 仿真结果与讨论 3.1 33 节点测试配电系统的仿真 3.2 69 节点测试配电系统仿真 4 结论 1 概述 为了使系统网损达到最低值&a…

AI Chat 设计模式:10. 组合模式

本文是该系列的第八篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 给我介绍一下组合模式A.1Q.2 好的,给我举一个组合模式的例子,使…

idea导入maven项目问题

问题产生原因: ①idea加载maven项目,如果网络不通畅,会在maven仓库中产生一个文件,如下图所示: ②当网络通畅时,在下载就会因为此文件导致无法下载正确的maven依赖 解决方案: ①打开maven仓库的根目录 ②…

SpringDataJpa 实体类—主键生成策略

主键配置 IdGeneratedValue(strategy GenerationType.IDENTITY)Column(name "cust_id")private Long custId;//主键 Id:表示这个注解表示此属性对应数据表中的主键GeneratedValue(strategy GenerationType.IDENTITY) 此注解表示配置主键的生成策…

Ubuntu 安装 Wireshark

Ubuntu 安装 Wireshark_ubuntu wireshark_iBlackAngel的博客-CSDN博客

ts中声明引入未使用的报错——解决方案

在编写ts项目的时候,经常会出现如下报错: 导入声明中的所有导入都未使用 这是因为导入的模块暂时没有使用,ts给的一个提示信息 解决方案: 在ts.config.json中 把noUnusedLocals 设置为false即可 {"compilerOptions"…

【雕爷学编程】Arduino动手做(175)---机智云ESP8266开发板模块4

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…

【UE5 多人联机教程】03-创建游戏

效果 步骤 打开“UMG_MainMenu”,增加创建房间按钮的点击事件 添加如下节点 其中,“FUNL Fast Create Widget”是插件自带的函数节点,内容如下: “创建会话”节点指游戏成功创建一个会话后,游戏的其他实例即可发现&am…

微服务体系<1>

我们的微服务架构 我们的微服务架构和单体架构的区别 什么是微服务架构 微服务就是吧我们传统的单体服务分成 订单模块 库存模块 账户模块单体模块 是本地调用 从订单模块 调用到库存模块 再到账户模块 这三个模块都是调用的同一个数据库 这就是我们的单体架构微服务 就是…

微信小程序如何实现页面传参?

前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递,下面我总结了 4 种页面方法。 路径传递 通过在url后面拼接参数,参数与路径之间使用 ? 分隔,参数键与参数值用 相连,不同参数用 & 分隔;如…

Training-Time-Friendly Network for Real-Time Object Detection 论文学习

1. 解决了什么问题? 目前的目标检测器很少能做到快速训练、快速推理,并同时保持准确率。直觉上,推理越快的检测器应该训练也很快,但大多数的实时检测器反而需要更长的训练时间。准确率高的检测器大致可分为两类:推理时…

银河麒麟安装mysql数据库(mariadb)-银河麒麟安装JDK-银河麒麟安装nginx(附安装包)

银河麒麟离线全套安装教程(手把手教程) 1.银河麒麟服务器系统安装mysql数据库(mariadb) 2.银河麒麟桌面系统安装mysql数据库(mariadb) 3.银河麒麟服务器系统安装JDK 4.银河麒麟桌面系统安装JDK 5.银河麒麟…

青大数据结构【2021】

一、单选(17!) 根据中序遍历得到降序序列可以知道,每个结点的左子树的结点的值比该结点的值小,因为没有重复的关键字,所以拥有最大值的结点没有左子树。 二、简答 三、分析计算 四、算法分析 3.迪杰斯特拉…

windows安装Elasticsearch8.9.0

官网解压安装好路径(非中文,无空格) 可参考 言之有李LAX csdn http://t.csdn.cn/S2oju本人使用jdk17 修改配置elasticsearch.yml xpack.security.enabled: false xpack.security.http.ssl:enabled: false直接点击bin\elasticsearch.bat…

Unity 工具之 NuGetForUnity 包管理器,方便在 Unity 中的进行包管理的简单使用

Unity 工具之 NuGetForUnity 包管理器,方便在 Unity 中的进行包管理的简单使用 目录 Unity 工具之 NuGetForUnity 包管理器,方便在 Unity 中的进行包管理的简单使用 一、简单介绍 二、NuGetForUnity 的下载导入 Unity 三、NuGetForUnity 在 Unity 的…

LeetCode 75 第十二题(11)盛最多水的容器

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 配合着示例给出的图片我们可以得知找出盛水最多的容器是什么意思,给一个数组,找出数组中两个元素能围成的最大的矩阵面积是多少. 比较直观的想法是套两层for循环暴力解出来,但是这题是中等难度题,一般中等题是没法用暴力得…

pinia在vue3中的使用

总结: 在store文件夹中建一个pinia的文件userStore.js 1.要想使用pinia必须先引入defineStore 这里我们使用es6的模块化语法导出的 import { defineStore } from pinia 2.然后使用export const useUserStore defineStore(user,{}) defineStore 方法有两个参数&…

论文分享:PowerTCP: Pushing the Performance Limits of Datacenter Networks

1 原论文的题目(中英文)、题目中包含了哪些关键词?这些关键词的相关知识分别是什么? 题目:PowerTCP: Pushing the Performance Limits of Datacenter Networks PowerTCP:逼近数据中心的网络性能极限 2 论…

git源码安装(无sudo权限)

git源码安装(无sudo权限) 下载源码解压安装添加到环境变量 下载源码 去https://mirrors.edge.kernel.org/pub/software/scm/git/下载需要的版本。我下载的是2.41.0版本 wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.41.0.tar.gz解…