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

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.lryc.cn/news/102100.html

相关文章:

  • 《MySQL45讲》笔记—索引
  • Android usb host模式通信示例
  • 开源Blazor UI组件库精选:让你的Blazor项目焕然一新!
  • MATLAB RANSAC圆柱体点云拟合 (28)
  • 【AI】《动手学-深度学习-PyTorch版》笔记(七):自动微分
  • vuejs源码阅读之代码生成器
  • 【MySQL】视图(十)
  • 面试手写实现Promise.all
  • TCP网络通信编程之字符流
  • 佰维存储面向旗舰智能手机推出UFS3.1高速闪存
  • 降龙十八掌
  • 【项目设计】MySQL 连接池的设计
  • Ubuntu系统adb开发调试问题记录
  • 【宏定义】——检验条件是否成立,并返回指定的值
  • UE5引擎源码小记 —反射信息注册过程
  • Redis缓存预热
  • Android 耗时分析(adb shell/Studio CPU Profiler/插桩Trace API)
  • 保护隐私与安全的防关联、多开浏览器
  • CloudStudio搭建Next框架博客_抛开电脑性能在云端编程(沉浸式体验)
  • 【FPGA IP系列】FIFO深度计算详解
  • JavaScript中语句和表达式
  • 打卡力扣题目十
  • UniApp实现API接口封装与请求方法的设计与开发方法
  • 利用小波分解信号,再重构
  • QT数据库编程
  • 基于stm32单片机的直流电机速度控制——LZW
  • 实际项目中使用mockjs模拟数据
  • 【家庭公网IPv6】
  • 【iOS】Frame与Bounds的区别详解
  • SpringBoot百货超市商城系统 附带详细运行指导视频