代理类必须实现与目标对象相同的接口,否则无法无缝替换;其核心是选择性转发(如校验、日志、缓存),而非简单委托;应隐藏真实对象引用,通过构造函数注入;避免手动new,宜用di容器管理,并注意异步与性能问题。

代理类必须实现与目标对象相同的接口
这是代理模式能正常工作的前提。如果目标类 RealSubject 实现了 IFileProcessor,那么代理类 FileProcessorProxy 也必须实现该接口,否则无法在不修改调用方代码的前提下替换对象。
常见错误是代理类只持有目标对象、却不实现相同接口,导致编译失败或运行时类型不匹配。接口定义应聚焦行为契约,例如:
public interface IFileProcessor
{
string Process(string path);
}
只要调用方依赖的是 IFileProcessor,就能无缝切换真实对象和代理对象。
代理类在方法中控制对真实对象的访问
代理的核心逻辑不是“转发”,而是“有选择地转发”——比如加日志、校验权限、缓存结果或延迟加载。直接无条件调用 real.Process(path) 只是委托,不算真正意义上的代理。
- 需要前置逻辑(如检查文件路径合法性)就放在调用前
- 需要后置处理(如记录耗时)就放在调用后
- 可选择不调用真实对象(如缓存命中时直接返回)
示例中常见的写法:
public string Process(string path)
{
if (!File.Exists(path))
throw new ArgumentException("File not found");
var sw = Stopwatch.StartNew();
var result = _real.Process(path); // 真实逻辑
sw.Stop();
Console.WriteLine($"Processed in {sw.ElapsedMilliseconds}ms");
return result;
}
避免在代理中暴露真实对象引用
如果代理类公开了 RealSubject 属性(如 public RealSubject Target { get; }),调用方可能绕过代理直接操作真实对象,使代理失效。
正确做法是将真实对象设为私有只读字段,并通过构造函数注入:
private readonly IFileProcessor _real;
public FileProcessorProxy(IFileProcessor real)
{
_real = real ?? throw new ArgumentNullException(nameof(real));
}
这样既保证了依赖可测(支持 Mock),又防止外部跳过代理逻辑。
代理模式不等于装饰器或 AOP,别滥用 new
每次手动 new FileProcessorProxy(new RealSubject()) 是可行的,但容易失控。实际项目中要注意:
- 代理对象本身也应被容器管理(如 .NET Core 的 DI 容器注册为 Scoped/Transient)
- 若需多层代理(日志 + 权限 + 重试),硬编码嵌套会难维护,此时更适合用拦截器(如 Castle DynamicProxy)或中间件
- 同步代理没问题,但若涉及异步(
Task<string> ProcessAsync()</string>),代理方法必须同样声明为async并await,否则会丢失上下文或引发死锁
最易忽略的一点:代理类自己不能成为性能瓶颈。比如在 Process() 里做耗时 IO 或锁操作,反而拖慢整个调用链。











