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语句抛出一个异常对象,从而使得程序进入异常处理流程。
相关文章:
Python代理模式介绍、使用
一、Python代理模式介绍 Python代理模式(Proxy Pattern)是一种结构型设计模式。在代理模式中,代理对象充当了另一个对象的占位符,以控制对该对象的访问。 代理对象和被代理对象实现了相同的接口,因此它们可以互相替代…...
《MySQL45讲》笔记—索引
索引 索引是为了提高数据查询效率,就像书的目录一样。如下图,索引和数据就是位于存储引擎中: 索引常见模型 哈希表 以键值对存储的数据结构。适用于只有等值查询的场景。 有序数组 在等值查询和范围查询场景中性能都特别优秀。但是有…...
Android usb host模式通信示例
当使用Android设备作为USB主机时,可以使用Android提供的USB API来进行USB通信。下面是一个简单的Android USB通信的示例。在这个示例中,我们将发送一条消息到连接的USB设备并从USB设备接收响应。 首先,在AndroidManifest.xml文件中添加以下权…...
开源Blazor UI组件库精选:让你的Blazor项目焕然一新!
今天给大家推荐一些开源、美观的Blazor UI组件库,这些优秀的开源框架和项目不仅能够帮助开发者们提高开发效率,还能够为他们的项目带来更加丰富的用户体验。 注:排名不分先后,都是十分优秀的开源框架和项目 Ant Design Blazor…...
MATLAB RANSAC圆柱体点云拟合 (28)
MATLAB RANSAC圆柱体点云拟合 (28) 一、算法介绍二、函数介绍三、算法实现四、效果展示一、算法介绍 RANSAC拟合方法,从原始点云中拟合具有特定形状的点云,这里对原始点云中大致呈圆柱的点云进行分割,圆柱的半径,以及朝向都是比较重要的定义圆柱的参数。下面是具体使用的…...
【AI】《动手学-深度学习-PyTorch版》笔记(七):自动微分
AI学习目录汇总 1、什么是自动微分 自动微分:automatic differentiation,深度学习框架通过自动计算导数,即自动微分,自动微分使系统能够随后反向传播梯度。 计算图:computational graph,根据设计好的模型,系统会构建一个计算图, 来跟踪计算是哪些数据通过哪些操作组合…...
vuejs源码阅读之代码生成器
代码生成器是模版编译的最后以后,它的作用是将AST转换成渲染函数中的内容,这个内容可以称为代码字符串。 代码字符串可以被包装在函数中执行,这个函数就是我们通常说的渲染函数。 渲染函数被执行之后,可以生成一份VNode…...
【MySQL】视图(十)
🚗MySQL学习第十站~ 🚩本文已收录至专栏:MySQL通关路 ❤️文末附全文思维导图,感谢各位点赞收藏支持~ 一.引入 视图(View)是一种虚拟存在的表。视图中的数据并不在数据库中实际存在,行和列数据…...
面试手写实现Promise.all
目录 前言常见面试手写系列Promise.resolve 简要回顾源码实现Promise.reject 简要回顾源码实现Promise.all 简要回顾源码实现Promise.allSettled 简要回顾源码实现Promise.race 简单回顾源码实现结尾 前言 (?﹏?)曾经真实发生在一个朋友身上的真实事件,面试官让…...
TCP网络通信编程之字符流
【案例1】 【题目描述】 【 注意事项】 (3条消息) 节点流和处理流 字符处理流BufferedReader、BufferedWriter,字节处理流-BufferedInputStream和BufferedOutputStream (代码均正确且可运行_Studying~的博客-CSDN博客 1。这里需要使用字符处理流,来将…...
佰维存储面向旗舰智能手机推出UFS3.1高速闪存
手机“性能铁三角”——SoC、运行内存、闪存决定了一款手机的用户体验和定位,其中存储器性能和容量对用户体验的影响越来越大。 针对旗舰智能手机,佰维推出了UFS3.1高速闪存,写入速度最高可达1800MB/s,是上一代通用闪存存储的4倍以…...
降龙十八掌
目录 大数据: 1 HIVE: 1.1 HIVE QL 1.1.1 创建表 1.1.2 更新表 1.1.3 常用语句 1.2 hive参数配置 大数据: 1 HIVE: 1.1 HIVE QL DDL中常用的命令有:create,drop,alter,trunc…...
【项目设计】MySQL 连接池的设计
目录 👉关键技术点👈👉项目背景👈👉连接池功能点介绍👈👉MySQL Server 参数介绍👈👉功能实现设计👈👉开发平台选型👈👉MyS…...
Ubuntu系统adb开发调试问题记录
Ubuntu系统adb开发调试问题记录 一、adb devices no permissions二、自定义adb server端口三、动态库目录四、USB抓包 一、adb devices no permissions lsusb -t 设备树直观地查看设备的Bus ID和Device Num,lsusb找到对应的PID和VID编辑udev规则 sudo vim /etc/ud…...
【宏定义】——检验条件是否成立,并返回指定的值
文章目录 功能说明实现示例解析扩展 功能说明 宏检验条件是否成立,并返回指定的值 #define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)TU_VERIFY(1) 检验为真,啥也不干TU_VERIFY(0) 校验为假&…...
UE5引擎源码小记 —反射信息注册过程
序 最近看了看反射相关的知识,用不说一点人话的方式来说,反射是程序在运行中能够动态获取修改或调用自身属性的东西。 一开始我是觉得反射用处好像不大,后续查了下一些反射的使用环境,发现我格局小了,我觉得用处不大的…...
Redis缓存预热
说明:项目中使用到Redis,正常情况,我们会在用户首次查询数据的同时把该数据按照一定命名规则,存储到Redis中,称为冷启动(如下图),这种方式在一些情况下可能会给数据库带来较大的压力…...
Android 耗时分析(adb shell/Studio CPU Profiler/插桩Trace API)
1.adb logcat 查看冷启动时间和Activity显示时间: 过滤Displayed关键字,可看到Activity的显示时间 那上面display后面的是时间是指包含哪些过程的时间呢? 模拟在Application中沉睡1秒操作,冷启动情况下: 从上可知&…...
保护隐私与安全的防关联、多开浏览器
随着互联网的不断发展,我们越来越离不开浏览器这个工具,它为我们提供了便捷的网络浏览体验。然而,随着我们在互联网上的活动越来越多,我们的个人信息和隐私也日益暴露在网络风险之下。在这种背景下,为了保护个人隐私和…...
CloudStudio搭建Next框架博客_抛开电脑性能在云端编程(沉浸式体验)
文章目录 ⭐前言⭐进入cloud studio工作区指引💖 注册coding账号💖 选择cloud studio💖 cloud studio选择next.js💖 安装react的ui框架(tDesign)💖 安装axios💖 代理请求跨域&#x…...
生成xcframework
打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式,可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
stm32G473的flash模式是单bank还是双bank?
今天突然有人stm32G473的flash模式是单bank还是双bank?由于时间太久,我真忘记了。搜搜发现,还真有人和我一样。见下面的链接:https://shequ.stmicroelectronics.cn/forum.php?modviewthread&tid644563 根据STM32G4系列参考手…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
【python异步多线程】异步多线程爬虫代码示例
claude生成的python多线程、异步代码示例,模拟20个网页的爬取,每个网页假设要0.5-2秒完成。 代码 Python多线程爬虫教程 核心概念 多线程:允许程序同时执行多个任务,提高IO密集型任务(如网络请求)的效率…...
