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

Python设计模式:代理模式

1. 什么是代理模式

代理模式(Proxy Pattern)是一种结构型设计模式,它为其他对象提供一种代理以控制对这个对象的访问。代理模式通过引入一个代理对象来间接访问真实对象,从而在不改变真实对象的情况下,增加对其访问的控制和管理。

在软件开发中,直接访问某个对象可能会涉及到复杂的操作、资源管理或安全问题。例如,在处理大型对象时,可能不希望在程序启动时就加载所有数据,而是希望在真正需要时才进行加载。此外,某些对象可能需要进行权限检查、日志记录或其他操作,这些都可以通过代理模式来实现。

代理模式的主要作用包括:

  1. 控制访问:代理可以在访问真实对象之前进行权限检查或其他控制,确保只有合适的请求才能访问真实对象。

  2. 延迟加载:通过代理,可以在需要时才加载真实对象,从而节省资源。例如,在处理大型数据时,可以使用代理来延迟对象的创建,直到真正需要时才进行初始化。

  3. 记录日志:代理可以在调用真实对象的方法时记录日志,方便后续的调试和分析。这对于监控系统的行为和性能非常有帮助。

  4. 远程代理:在分布式系统中,代理可以代表远程对象进行操作,隐藏网络通信的复杂性。客户端可以像访问本地对象一样访问远程对象,从而简化了编程模型。

  5. 缓存:代理可以实现对真实对象的结果进行缓存,以提高性能。例如,在网络请求中,代理可以缓存之前的请求结果,避免重复的网络调用。

2. 示例 1:图像加载代理

在实际开发中,图像加载是一个常见的场景,尤其是在图形用户界面(GUI)应用程序中。加载高分辨率图像可能会消耗大量的内存和时间,因此我们可以使用代理模式来实现延迟加载。

class RealImage:
    def __init__(self, filename):
        self.filename = filename
        self.load_image_from_disk()

    def load_image_from_disk(self):
        print(f"Loading {self.filename}")

    def display(self):
        print(f"Displaying {self.filename}")


class ProxyImage:
    def __init__(self, filename):
        self.filename = filename
        self.real_image = None

    def display(self):
        if self.real_image is None:
            self.real_image = RealImage(self.filename)  # 延迟加载
        self.real_image.display()


if __name__ == "__main__":
    # 创建代理对象
    proxy_image = ProxyImage("test_image.jpg")

    # 第一次调用 display 方法时,图像会被加载
    proxy_image.display()

    # 再次调用 display 方法时,图像不会被重新加载
    proxy_image.display()

Loading test_image.jpg
Displaying test_image.jpg
Displaying test_image.jpg

3. 示例 2:网络请求代理

在现代应用程序中,网络请求是一个常见的场景。为了提高性能和安全性,我们可以使用代理模式来管理网络请求。以下是一个复杂的示例,展示如何使用代理模式来实现网络请求的缓存和日志记录。

import requests
import time
import json

# 真实主题(Real Subject)
class RealNetworkRequest:
    def __init__(self, url):
        self.url = url

    def fetch_data(self):
        print(f"Fetching data from {self.url}")
        response = requests.get(self.url)
        return response.json()

# 代理(Proxy)
class ProxyNetworkRequest:
    def __init__(self, url, user_role):
        self.url = url
        self.real_request = RealNetworkRequest(url)
        self.cache = {}
        self.log_file = "request_log.txt"
        self.user_role = user_role  # 用户角色

    def fetch_data(self):
        # 权限检查
        if not self.check_access():
            print("Access denied: You do not have permission to access this resource.")
            return None

        # 检查缓存
        if self.url in self.cache:
            print("Returning cached data.")
            return self.cache[self.url]

        # 记录请求开始时间
        start_time = time.time()

        # 发送请求
        data = self.real_request.fetch_data()

        # 将数据存入缓存
        self.cache[self.url] = data

        # 记录请求结束时间
        end_time = time.time()
        self.log_request(start_time, end_time)

        return data

    def check_access(self):
        # 简单的权限检查逻辑
        # 这里可以根据实际需求进行更复杂的权限检查
        return self.user_role == "admin"  # 只有 admin 用户可以访问

    def log_request(self, start_time, end_time):
        duration = end_time - start_time
        log_entry = f"Requested {self.url} in {duration:.2f} seconds\n"
        with open(self.log_file, "a") as log:
            log.write(log_entry)

# 客户端代码
if __name__ == "__main__":
    url = "https://jsonplaceholder.typicode.com/posts/1"
    
    # 创建代理对象,用户角色为 "admin"
    proxy_request = ProxyNetworkRequest(url, user_role="admin")

    # 第一次调用 fetch_data 方法时,数据会被请求并缓存
    data = proxy_request.fetch_data()
    print("Data:", json.dumps(data, indent=2))

    # 再次调用 fetch_data 方法时,数据将从缓存中返回
    data = proxy_request.fetch_data()
    print("Data:", json.dumps(data, indent=2))

    # 创建代理对象,用户角色为 "guest"
    proxy_request_guest = ProxyNetworkRequest(url, user_role="guest")

    # 尝试调用 fetch_data 方法,应该会被拒绝
    data = proxy_request_guest.fetch_data()
    print("Data:", json.dumps(data, indent=2))
Fetching data from https://jsonplaceholder.typicode.com/posts/1
Data: {
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Returning cached data.
Data: {
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto"
}
Access denied: You do not have permission to access this resource.
Data: null
  • 真实主题(RealNetworkRequest):负责发送网络请求并获取响应。
  • 代理(ProxyNetworkRequest)
    • 权限检查:在 fetch_data 方法中添加了 check_access 方法,检查用户角色是否为 “admin”。只有管理员用户才能访问网络请求。
    • 缓存和日志记录:与之前的示例相同,代理类在发送请求之前检查缓存,并在请求后记录日志。
  • 客户端代码:创建两个代理对象,一个是管理员用户,另一个是访客用户。管理员用户可以成功获取数据,而访客用户则会被拒绝访问。
http://www.dtcms.com/a/108020.html

相关文章:

  • 看行业DeepSeekR1模型如何构建及减少推理大模型过度思考
  • IntelliJ IDEA全栈Git指南:从零构建到高效协作开发
  • 洛谷题单3-P1009 [NOIP 1998 普及组] 阶乘之和-python-流程图重构
  • vue中的 拖拽
  • @ComponentScan注解详解:Spring组件扫描的核心机制
  • 【力扣hot100题】(037)翻转二叉树
  • 每日一题---买卖股票的最好时机(一)、(二)
  • 【每日算法】Day 15-1:哈希表与布隆过滤器——海量数据处理与高效检索的核心技术(C++实现)
  • ollama本地部署大模型(命令行)
  • Eclipse IDE
  • 基本元素定位(findElement方法)
  • 【嵌入式Linux】U-Boot源码分析
  • JMeter接口自动化发包与示例
  • Windows连接服务器Ubuntu_MobaXterm
  • 【Mysql】基础(函数,约束,多表查询,事务)
  • PHP语言基础
  • 深入解析C++类:面向对象编程的核心基石
  • 前端css+html面试题
  • 面向对象分析与设计的多过程多层级实现
  • Generic Mapping Tools(GMT):开源的地球、海洋和行星科学的工具箱、Python与matlab包
  • 从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.2知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)
  • uniapp 微信小程序 使用ucharts
  • 实战打靶集锦-36-Deception
  • 封装可拖动弹窗(vue jquery引入到html的版本)
  • SQL语句(一)—— DDL
  • [Lc6_记忆化搜索] 最长递增子序列 | 矩阵中的最长递增路径
  • 【大模型系列篇】大模型基建工程:使用 FastAPI 构建 SSE MCP 服务器
  • 14-SpringBoot3入门-MyBatis-Plus之CRUD
  • 树莓派超全系列文档--(15)无需交互使用raspi-config工具其二
  • clickhouse集群版本部署文档