Unity 代理模式
初学者,自用笔记
用于在不改变目标对象对外接口的前提下,通过一个替身对象(Proxy)来控制对目标对象的访问:比如延迟加载、权限校验、网络转发、线程切换、缓存、日志与性能统计等。
- Subject/IChunk(抽象主题/服务接口):目标与代理共同实现的接口(例如 IAssetProvider、IService、- IRepository)。
- RealSubject/RealChunk(真实主题/实际服务):真正干活的对象(例如真实资源加载器、真实网络服务、真实存档仓库)。
- Proxy(代理):实现同一 Subject 接口,内部持有 RealSubject(或其创建方式),在转发前后附加控制逻辑。实现方法有虚代理、保护代理、远程代理等等......
简单例子
ICkunk
// Subject:服务接口(调用方只依赖它)
public interface IProfileService
{
Task<string> GetPlayerNameAsync();
}
RealChunk
// RealSubject:真实服务(真正干活,可能初始化很重)
public sealed class RealProfileService : IProfileService
{
public RealProfileService()
{
// 假设初始化很重(网络/缓存/鉴权等)
Console.WriteLine("[RealProfileService] init heavy stuff...");
}
public async Task<string> GetPlayerNameAsync()
{
await Task.Delay(100); // 模拟网络/IO
return "Alice";
}
}
Proxy
代理(Proxy)这个中间层的核心价值是:不改调用方代码、不改(或尽量少改)真实服务代码,但能在访问真实对象前后插入控制逻辑,并且在类型层面做到可替换(接口不变)
// Proxy:代理(同接口,控制访问:懒加载 + 可附加日志/缓存/校验)
public sealed class ProfileServiceProxy : IProfileService
{
private RealProfileService _real;
public async Task<string> GetPlayerNameAsync()
{
// 虚代理:用到才创建真实对象
_real ??= new RealProfileService();
Console.WriteLine("[Proxy] Before call");
var name = await _real.GetPlayerNameAsync();
Console.WriteLine("[Proxy] After call");
return name;
}
}
Client
// Client:调用方(不关心是真实服务还是代理)
public static class ProxyDemo
{
public static async Task Main()
{
IProfileService service = new ProfileServiceProxy();
// 第一次调用才触发 RealProfileService 的初始化
var name = await service.GetPlayerNameAsync();
Console.WriteLine($"PlayerName = {name}");
}
}