设计模式实战:代理模式(Proxy)

在很多系统中,我们并不会直接访问某个对象,而是通过一个"中间层"来完成访问。

例如:

  • 访问远程服务(RPC)
  • 数据库懒加载
  • 权限控制
  • 缓存代理
  • 日志记录

客户端看起来是在访问对象本身,但实际上中间有一层"代理"。

这就是 代理模式(Proxy)


一、代理模式解决什么问题?

一句话:

为一个对象提供一个替身(代理),以控制对该对象的访问。

关键词:

  • 控制访问
  • 延迟加载
  • 权限控制
  • 远程访问

代理对象与真实对象实现 相同接口,客户端并不知道自己访问的是代理还是原对象。


二、一个典型场景:图片懒加载

假设系统中需要加载图片,但图片文件很大:

  • 加载速度慢
  • 占用内存
  • 可能根本不会被使用

如果直接创建对象:

python 复制代码
class RealImage:

    def __init__(self, filename):
        self.filename = filename
        self.load_from_disk()

    def load_from_disk(self):
        print(f"加载图片: {self.filename}")

    def display(self):
        print(f"显示图片: {self.filename}")

创建对象时就会立即加载:

python 复制代码
image = RealImage("photo.jpg")

如果系统中有很多图片,这会严重影响性能。


三、引入代理对象

我们可以创建一个代理类,在真正需要时才加载图片。

python 复制代码
class ImageProxy:

    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()

使用方式:

python 复制代码
image = ImageProxy("photo.jpg")

# 此时并不会加载图片
image.display()

输出:

复制代码
加载图片: photo.jpg
显示图片: photo.jpg

图片只有在 真正使用时才加载

这就是 虚拟代理(Virtual Proxy)


四、代理模式结构

代理模式通常包含三个角色:

1️⃣ Subject(抽象接口)

定义真实对象与代理对象的共同接口。

2️⃣ RealSubject(真实对象)

真正执行业务逻辑的对象。

3️⃣ Proxy(代理对象)

控制对真实对象的访问。

结构示意:

复制代码
Client
  |
Proxy
  |
RealSubject

客户端只依赖接口,不关心具体实现。


五、Python 版本的完整示例

先定义统一接口:

python 复制代码
from abc import ABC, abstractmethod

class Image(ABC):

    @abstractmethod
    def display(self):
        pass

真实对象:

python 复制代码
class RealImage(Image):

    def __init__(self, filename):
        self.filename = filename
        self.load()

    def load(self):
        print(f"加载图片: {self.filename}")

    def display(self):
        print(f"显示图片: {self.filename}")

代理对象:

python 复制代码
class ImageProxy(Image):

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

    def display(self):

        if not self.real_image:
            self.real_image = RealImage(self.filename)

        self.real_image.display()

客户端:

python 复制代码
image = ImageProxy("test.jpg")

print("对象创建完成")

image.display()

运行结果:

复制代码
对象创建完成
加载图片: test.jpg
显示图片: test.jpg

可以看到:

  • 对象创建时没有加载图片
  • 第一次访问才真正创建对象

六、代理模式常见类型

代理模式有很多变种,常见的包括:

1 虚拟代理(Virtual Proxy)

控制资源加载,例如:

  • 图片懒加载
  • 大对象初始化

2 远程代理(Remote Proxy)

代表远程对象,例如:

  • RPC 调用
  • 微服务客户端
  • gRPC

客户端看起来像调用本地对象,其实是远程调用。


3 保护代理(Protection Proxy)

控制访问权限,例如:

  • 用户权限校验
  • API 权限控制

示例:

python 复制代码
if not user.is_admin:
    raise PermissionError

4 缓存代理(Cache Proxy)

在访问真实对象前增加缓存。

例如:

  • Redis 缓存
  • API 缓存
  • 查询缓存

七、代理模式 vs 装饰器模式

很多人会混淆这两个模式。

对比 代理模式 装饰器模式
目的 控制访问 增强功能
是否强调叠加 不强调 强调
使用场景 权限、远程、懒加载 日志、缓存、监控

一句话总结:

代理关注"控制访问",装饰器关注"增强功能"。


八、真实项目中的应用

代理模式在真实项目中非常常见。

例如:

1 ORM 懒加载

在 Django / SQLAlchemy 中:

python 复制代码
user.posts

第一次访问才会查询数据库。


2 RPC 客户端

调用远程服务:

python 复制代码
user_service.get_user(1001)

看起来像本地调用,其实是网络请求。


3 缓存代理

python 复制代码
def get_user(id):

    if cache.exists(id):
        return cache.get(id)

    user = db.query(id)
    cache.set(id, user)

    return user

缓存层本质上就是代理。


九、代理模式优缺点

优点

  • 控制对象访问
  • 支持懒加载
  • 可以增加权限控制
  • 可以加入缓存

缺点

  • 增加系统复杂度
  • 代理类可能变多
  • 调试时层级增加

十、一句话总结

代理模式的核心是:为对象增加一个"中间层",控制对对象的访问。

这个中间层可以实现:

  • 权限控制
  • 懒加载
  • 远程调用
  • 缓存

在现代系统中,代理模式几乎无处不在。

相关推荐
2401_8463395616 小时前
CSS如何优化大型项目样式_使用SASS预处理器提升开发效率
jvm·数据库·python
invicinble1 天前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
m0_674294641 天前
如何编写SQL存储过程性能对比_记录执行时间评估优化效果
jvm·数据库·python
运气好好的1 天前
怎样开启phpMyAdmin的操作审计日志_记录每条执行的SQL
jvm·数据库·python
2401_871492851 天前
Layui如何修改Layui默认的UI主题颜色(换肤功能实现)
jvm·数据库·python
南子北游1 天前
Python学习(基础语法1)
开发语言·python·学习
步辞1 天前
Redis如何利用LFU算法优化缓存命中率
jvm·数据库·python
forEverPlume1 天前
golang如何实现日志按级别过滤_golang日志按级别过滤实现教程
jvm·数据库·python
m0_624578591 天前
MySQL主从复制支持跨版本吗_不同版本间同步的注意事项
jvm·数据库·python
yuanpan1 天前
Python Pygame 入门教程:从零学会创建窗口、绘图和游戏交互
python·游戏·pygame