🎯 导读:代理模式是一个非常实用、在底层开发中随处可见的结构型设计模式。它的核心思想用一句话概括:**”不要直接碰那个真实的对象,找个替身(中介)来帮你办事。”** 本文配有 📊 UML类图 和 💻 完整代码案例,带你彻底掌握这个”替身”技巧!
🎭 1. 什么是代理模式?
代理模式(Proxy Pattern) 的核心思想:
“不要直接碰那个真实的对象,找个替身(中介)来帮你办事。”
代理对象拥有和真实对象完全相同的接口(看起来一模一样),但它会在你真正调用真实对象的方法之前,偷偷帮你做一些”额外的控制”——比如:
| 控制类型 | 作用 |
|---|---|
| ⏱️ 延迟加载 | 省内存,用到时才加载 |
| 🔒 权限校验 | 保安全,检查用户权限 |
| 📝 记录日志 | 追踪调用过程 |
| 💾 缓存结果 | 避免重复计算 |
🧩 2. 客户端需要知道哪些类?
你需要知道 2 个类:
- 🎯 抽象接口(Subject Interface) —— 用它来定义变量、调用方法
- 🎭 代理类(Proxy Class) ——
new出这个代理对象来帮你办事
你不需要/不应该知道的类:
- 🔒 真实目标类(Real Subject) —— 客户端完全被蒙在鼓里,它以为自己在使用真实对象,但其实一直在和代理打交道
classDiagram
class Client {
+ main()
}
class IGmshModel {
+ render3D()
+ getNodeCount()
}
class GmshProxy {
- filePath
- realModel
+ render3D()
+ getNodeCount()
- lazyLoad()
}
class RealGmshModel {
- filePath
+ render3D()
+ getNodeCount()
}
Client ..> IGmshModel : 依赖接口
Client ..> GmshProxy : 创建代理
GmshProxy ..> RealGmshModel : 延迟创建
IGmshModel <|.. GmshProxy : 实现
IGmshModel <|.. RealGmshModel : 实现
🎬 3. 生动的实战场景:小米的”虚假”网格模型
在开发复杂的工业软件(例如 小米 这样的拓扑优化系统)时,我们经常要解析外部的 CAD 模型或网格文件(比如 Gmsh 生成的 .msh 文件)。
❌ 痛点(没有代理模式)
假设用户导入了一个 5GB 大小的超精细 Gmsh 网格文件:
1 | 用户拖拽文件 → 系统立即读取 5GB → 界面卡死 120 秒 → 用户崩溃 💥 |
问题:用户只是想先看看项目结构,暂时并不想立即渲染或求解!
✅ 解法(虚拟代理模式 - Virtual Proxy)
我们给真实的网格模型找一个替身(Proxy):
1 | 用户拖拽文件 → 创建轻量级替身(瞬间完成)→ 界面秒开 ✅ |
延迟加载(Lazy Loading):只有当用户真正需要时,才加载真实数据!
📊 4. UML 类图详解
classDiagram
class IGmshModel {
+ render3D()
+ getNodeCount()
}
class RealGmshModel {
- filePath
+ RealGmshModel(path)
+ render3D()
+ getNodeCount()
}
class GmshProxy {
- filePath
- realModel
+ GmshProxy(path)
+ render3D()
+ getNodeCount()
- lazyLoad()
}
IGmshModel <|.. RealGmshModel : 实现
IGmshModel <|.. GmshProxy : 实现
GmshProxy o-- RealGmshModel : 组合(延迟创建)
🔑 三大核心角色
| 角色 | 类名 | 职责 | 比喻 |
|---|---|---|---|
| 🎯 抽象接口 | IGmshModel |
定义真实对象和代理的共同接口 | 网格模型的标准规格 |
| 🔒 真实目标类 | RealGmshModel |
真正干活的对象,又重又慢 | 5GB 的真实网格数据 |
| 🎭 代理类 | GmshProxy |
轻量级替身,控制对真实对象的访问 | 网格模型的”经纪人” |
💻 5. C++ 现代代码生动演绎
🎯 智能指针版(推荐)
1 |
|
📤 输出结果
1 | === 1. 用户拖拽导入了大型模型文件 === |
🎨 6. 对象结构图解
1 | 初始状态(用户刚导入文件): |
📋 7. 代理模式的变种与工业用途
在上面的例子中,我们实现的是**”虚拟代理(Virtual Proxy)”**,也就是为了延迟加载。除了这个,代理模式还有几个极其厉害的亲戚:
1. 🛡️ 保护代理(Protection Proxy)
用来做权限控制。客户端调用 proxy->deleteProject() 时:
- 代理先检查当前登录的用户是不是管理员
- 是 → 转发给真实对象
- 否 → 直接报错
classDiagram
class User {
+ role
}
class ProjectProxy {
+ deleteProject()
- checkPermission()
}
class RealProject {
+ deleteProject()
}
User ..> ProjectProxy : 调用
ProjectProxy ..> RealProject : 有权限时转发
2. 🌐 远程代理(Remote Proxy)
真实对象根本不在你的电脑上,而在云端服务器里(比如 RPC 远程过程调用)。
你调用的代理方法,其实是代理把请求打包成网络数据发给了服务器。
1 | 客户端 → 远程代理 → 网络请求 → 服务器 → 真实对象 |
3. 💾 缓存代理(Cache Proxy)
如果真实对象计算某个结果(比如高精度有限元求解)要很久,代理可以把上次算过的结果存起来。
下次再调同一个参数,代理直接把缓存返回,根本不去惊动真实对象。
classDiagram
class CalculationProxy {
- cache
+ calculate(params)
- checkCache(params)
}
class RealCalculator {
+ calculate(params)
}
CalculationProxy ..> RealCalculator : 缓存未命中时
🎯 8. 代理模式 vs 装饰模式
很多初学者觉得代理模式和装饰模式长得一模一样(都是一个类包着另一个同类型的类),但它们的意图完全不同:
classDiagram
title 代理模式 vs 装饰模式
class Client {
+ main()
}
class Subject {
+ operation()
}
class Proxy {
+ operation()
- controlAccess()
}
class RealSubject {
+ operation()
}
class Component {
+ operation()
}
class Decorator {
+ operation()
- addBehavior()
}
class ConcreteComponent {
+ operation()
}
Client ..> Proxy : 控制访问
Client ..> Decorator : 增强功能
Proxy ..> RealSubject : 保护/延迟
Decorator ..> ConcreteComponent : 包装
| 对比项 | 代理模式 | 装饰模式 |
|---|---|---|
| 🎯 目的 | “设关卡” —— 控制对真实对象的访问 | “加特技” —— 丰富功能 |
| 🔒 客户端是否知道真实对象 | ❌ 不知道,被隐藏 | ✅ 知道,自己包装 |
| 📝 典型场景 | 延迟加载、权限控制、远程访问 | 动态添加功能、组合特性 |
| 🎭 比喻 | 明星经纪人 | 煎饼加料 |
🎓 总结
代理模式是结构型模式中的实用利器,它完美诠释了:
🎯 “通过间接层来控制访问” 的设计哲学
通过引入代理对象,我们可以:
- ⏱️ 延迟加载 —— 省内存
- 🔒 权限控制 —— 保安全
- 📝 日志记录 —— 可追溯
- 💾 结果缓存 —— 提效率
📝 记忆口诀
“代理替身,控制访问;延迟加载,安全高效” 🎭
📝 本文通过 🎭 生活比喻、📊 UML类图、💻 完整代码案例,帮助你深入理解代理模式。希望对你有所帮助!
- 本文作者: 迪丽惹Bug
- 本文链接: https://lyroom.github.io/2026/04/27/代理模式详解/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!