Python 代理模式

Python 中的代理模式(Proxy Pattern)

代理模式是一种结构型设计模式,其核心目的是:
为另一个对象提供一个替身或占位符(代理),以控制对这个对象的访问

形象比喻:就像明星的经纪人——粉丝想找明星,只能通过经纪人(代理)联系,经纪人可以筛选、记录、延迟或增强请求。

代理模式的四种常见类型

  1. 虚拟代理(Virtual Proxy):延迟加载(懒加载),只有真正需要时才创建真实对象(节省资源)。
  2. 远程代理(Remote Proxy):代表网络另一端的对象(RPC、Web Service)。
  3. 保护代理(Protection Proxy):根据权限控制对真实对象的访问。
  4. 智能代理(Smart Proxy):在访问对象时添加额外行为(如计数、日志、缓存)。

Python 实现示例

1. 虚拟代理(懒加载)—— 最常见场景

适用于加载代价高昂的对象(如大图片、数据库连接、复杂计算)。

class Image:
    def __init__(self, filename):
        self.filename = filename
        print(f"加载图片 {filename}(这可能很慢!)")
        # 模拟耗时加载
        import time
        time.sleep(2)  # 模拟 IO 延迟

    def display(self):
        print(f"显示图片: {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 = Image(self.filename)  # 真正需要时才加载
        self._real_image.display()

# 使用
if __name__ == "__main__":
    image1 = ProxyImage("photo1.jpg")
    image2 = ProxyImage("photo2.jpg")

    print("代理创建完成,但图片还未加载")

    image1.display()  # 第一次调用:真正加载并显示
    image1.display()  # 第二次:直接显示,已缓存

    image2.display()  # 加载并显示

输出

代理创建完成,但图片还未加载
加载图片 photo1.jpg(这可能很慢!)
显示图片: photo1.jpg
显示图片: photo1.jpg
加载图片 photo2.jpg(这可能很慢!)
显示图片: photo2.jpg
2. 保护代理(权限控制)
class SensitiveData:
    def __init__(self):
        self.data = "超级机密信息:银行账户 = 123456789"

    def read(self):
        print(f"读取数据: {self.data}")

    def write(self, new_data):
        print(f"写入数据: {new_data}")
        self.data = new_data

class ProtectionProxy:
    def __init__(self, real_subject: SensitiveData, user_role: str):
        self._real_subject = real_subject
        self._user_role = user_role

    def read(self):
        if self._user_role in ["admin", "user"]:
            self._real_subject.read()
        else:
            print("权限不足:无法读取")

    def write(self, new_data):
        if self._user_role == "admin":
            self._real_subject.write(new_data)
        else:
            print("权限不足:只有管理员可写")

# 使用
data = SensitiveData()
proxy_admin = ProtectionProxy(data, "admin")
proxy_user = ProtectionProxy(data, "user")
proxy_guest = ProtectionProxy(data, "guest")

proxy_admin.read()   # 允许
proxy_admin.write("新数据")  # 允许

proxy_user.read()    # 允许
proxy_user.write("尝试修改")  # 拒绝

proxy_guest.read()   # 拒绝
3. 智能代理(日志 + 缓存)
class ExpensiveComputation:
    def compute(self, x):
        print(f"执行昂贵计算 for {x}...")
        import time
        time.sleep(1)
        return x ** x

class SmartProxy:
    def __init__(self):
        self._real = ExpensiveComputation()
        self._cache = {}  # 缓存结果

    def compute(self, x):
        print(f"[代理] 请求计算 {x}")
        if x not in self._cache:
            self._cache[x] = self._real.compute(x)
            print(f"[代理] 缓存新结果")
        else:
            print(f"[代理] 从缓存返回")
        return self._cache[x]

# 使用
proxy = SmartProxy()
print(proxy.compute(5))   # 真正计算
print(proxy.compute(5))   # 缓存命中
print(proxy.compute(10))  # 真正计算

代理模式结构总结

角色说明
Subject公共接口(Image / SensitiveData)
RealSubject真实对象
Proxy代理对象,控制访问、添加行为
Client使用 Subject 接口的代码

代理模式 vs 装饰器模式 vs 适配器模式

模式目的是否持有真实对象是否改变接口
代理控制访问(懒加载、权限、日志)不改变
装饰器增强功能(添加职责)不改变
适配器转换接口改变

关键区别

  • 代理和装饰器都保持接口不变,但代理更注重“控制访问”,装饰器更注重“增强行为”。
  • 代理常用于资源管理、权限、安全;装饰器常用于功能叠加。

Python 中的实际应用场景

  • Web 框架中的数据库连接代理(连接池)
  • ORM 中的懒加载属性(如 SQLAlchemy 的关系字段)
  • 缓存代理(如 Redis 缓存代理)
  • API 客户端的认证代理(自动添加 token)
  • 文件访问代理(权限检查)

Pythonic 简化方式

很多时候可以用属性描述符(@property)或第三方库实现代理:

class LazyProperty:
    def __init__(self, func):
        self.func = func

    def __get__(self, obj, cls):
        if obj is None:
            return self
        value = self.func(obj)
        setattr(obj, self.func.__name__, value)  # 缓存
        return value

class BigObject:
    @LazyProperty
    def heavy_data(self):
        print("加载大数据...")
        return {"data": "very large"}

obj = BigObject()
print("创建对象")
print(obj.heavy_data)  # 第一次加载
print(obj.heavy_data)  # 第二次直接返回

总结建议

  • 使用代理模式 当你需要控制访问、延迟加载、添加安全检查时。
  • 优先使用对象组合 实现代理(Python 推荐)。
  • 不要滥用:如果只是增强功能,考虑装饰器;如果是接口转换,用适配器。

如果你想看更高级的例子(如远程代理模拟、结合 asyncio 的异步代理、缓存代理实现),或者与其他模式对比的实际项目案例,欢迎继续问!

文章已创建 3511

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部