在Unity开发中, 代理模式(Proxy Pattern)用于为一个对象提供”代理”(替代品), 通过代理控制对原有对象的访问. 代理可以在不修改元对象的前提下, 添加额外功能(如权限校验\ 日志记录\ 延迟加载\ 缓存等), 同时保持与元对象相同的接口, 让客户端无感地使用.
 

举个具体场景: 大型资源加载代理

游戏中经常需要加载大型资源(如场景\ 高精度模型\ 动画片段), 直接加载可能由这些问题:
  • 加载前需要显示”加载中”UI, 加载后隐藏;
  • 加载过程中需要记录日志(如加载耗时);
  • 重复加载同一资源时, 需要缓存结果避免重复消耗性能;
  • 未解锁的资源需要校验权限, 禁止加载.
 
如果把这些逻辑直接写在资源加载器里, 会导致加载器职责混乱(既要加载资源, 又要处理UI\ 日志\ 权限). 代理模式可以解决这个问题: 用”资源加载代理”包装真实加载器, 代理负责处理附加逻辑, 真实加载器只专注于”加载资源”本身.
 

代理模式的核心角色

  1. 抽象主题(Subject): 定义真实对象和代理的共同接口(如”加载资源”方法), 确保代理可替代真实对象.
  1. 真实主题(Real Subject): 实现核心功能(如实际加载资源), 是被代理的对象.
  1. 代理(Proxy): 实现抽象主题接口, 持有真实主题的引用, 在调用真实主题方法前后添加额外逻辑(如UI显示\ 日志\ 缓存等).
 

代码实现步骤

  1. 定义抽象主题(资源加载接口)
先定义资源加载的投以接口, 确保真实加载器和代理都实现相同的方法:
 
  1. 实现真实主题(核心加载逻辑)
真实加载器只负责最核心的资源加载, 不处理任何附加逻辑
 
  1. 实现代理(添加附加逻辑)
代理持有真实加载器的引用, 在调用其他方法前后添加额外功能(UI\日志\缓存\权限校验等):
 
  1. 客户端使用(无感知调用)
客户端只需要依赖抽象接口 IResourceLoader , 无需关心使用的是真实加载器还是代理, 实现解耦:
 

代理模式的核心价值

  1. 功能增强, 不修改原对象: 真实加载器(RealResourceLoader )只负责加载, 代理( ResourceLoaderProxy ) 添加了 UI\日志\缓存\权限校验等功能, 符合”对修改封闭, 对扩展开放”
  1. 控制访问: 通过代理可以拦截对真实对象的访问(如禁止加载未解锁资源), 或延迟加载(需要时才调用真实加载器).
  1. 解耦职责: 将”核心功能”与”附加功能”分离, 真实对象专注于本质工作, 代理专注于辅助逻辑, 符合单一职责原则.
 

常见代理类型及 Unity 场景

  • 远程代理: 在网络同步中, 代理本地对象与远程服务器对象通信(如多人游戏中, 本地代理同步远程玩家状态)
  • 虚拟代理: 延迟加载大型资源(如只有当相机视野包含某物体时, 代理才触发真实加载)
  • 保护代理: 控制对象访问权限(如上述例子中的资源解锁校验)
  • 缓存代理: 缓存频繁访问的资源(如上述例子中的 _resourceCache )
 

代理模式 vs 装饰器模式

  • 代理模式: 访问控制, 重点是”要不要访问原对象”以及”访问前后做什么”(如权限\缓存)
  • 装饰器模式: 增强功能, 重点是”在原对象功能基础上叠加新功能”(如给攻击加火焰\暴击效果)
 
总结: 代理模式就像”秘书” ——— 你(客户端)想找老板(真实对象)谈事情, 先通过秘书(代理), 秘书会先确认你有没有预约(权限校验)\记录会面时间(日志)\如果老板忙就让你先等(延迟访问), 但最终还是会让你和老板沟通. 在Unity中, 它是”在不侵入核心逻辑的前提下增强功能”的利器