代理(Proxy)模式的核心思想可以表述为:
代理是一个"替身"对象,它控制对原始对象(目标对象)的访问,并在调用前后插入额外逻辑(如日志、事务、权限检查等),而客户端通常 unaware(无感知)自己正在和代理交互。
✅ 一、代理的本质:包装 + 增强
| 角色 | 作用 |
|---|---|
| 目标对象(Target) | 真正干活的类(如 OrderService) |
| 代理对象(Proxy) | 外表看起来和目标一模一样,但内部会先做些额外事情,再决定是否/如何调用目标 |
| 客户端(Client) | 只知道接口或基类,不知道实际用的是目标还是代理 |
🔍 二、举个生活化的例子 🌰
想象你请了一个私人助理(Proxy):
- 你想见 CEO(目标对象)
- 但 CEO 很忙,不会直接见你
- 你只能联系助理
- 助理会:
- 先检查你的预约(权限验证)
- 记录你来访的时间(日志)
- 确认 CEO 有空才带你进去(调用真实方法)
- 甚至有时候直接替 CEO 回答你(缓存)
💼 你感觉是在和 CEO 沟通,其实全程是助理在处理。
💻 三、代码示例:静态代理 vs 动态代理
1️⃣ 静态代理(手写)
csharp
public interface IOrderService
{
void CreateOrder(string id);
}
// 真实服务
public class OrderService : IOrderService
{
public void CreateOrder(string id) => Console.WriteLine($"创建订单: {id}");
}
// 手写的代理类
public class LoggingOrderProxy : IOrderService
{
private readonly IOrderService _realService;
public LoggingOrderProxy(IOrderService realService)
{
_realService = realService;
}
public void CreateOrder(string id)
{
Console.WriteLine("【日志】开始创建订单");
_realService.CreateOrder(id); // 调用真实对象
Console.WriteLine("【日志】订单创建完成");
}
}
// 客户端使用
var proxy = new LoggingOrderProxy(new OrderService());
proxy.CreateOrder("123");
// 输出:
// 【日志】开始创建订单
// 创建订单: 123
// 【日志】订单创建完成
✅ 客户端只依赖 IOrderService,完全不知道背后是代理还是真实对象。
2️⃣ 动态代理(如 Castle DynamicProxy、.NET 的 RealProxy)
你不用手写代理类,框架在运行时自动生成!
csharp
// 使用 Castle DynamicProxy
var generator = new ProxyGenerator();
var interceptor = new LoggingInterceptor();
// 动态生成一个 IOrderService 的代理对象
var proxy = generator.CreateInterfaceProxyWithTarget<IOrderService>(
target: new OrderService(),
interceptor: interceptor
);
proxy.CreateOrder("123"); // 自动触发拦截器逻辑
其中 LoggingInterceptor 定义增强逻辑:
csharp
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"【拦截】调用方法: {invocation.Method.Name}");
invocation.Proceed(); // 调用真实方法
Console.WriteLine($"【拦截】方法结束");
}
}
🔸 这个代理类是运行时动态生成的 IL 代码,不是你写的,但行为和静态代理一致。
✅ 四、代理的常见用途
| 场景 | 说明 |
|---|---|
| AOP(面向切面编程) | 日志、性能监控、异常处理 |
| 安全控制 | 权限验证、访问拦截 |
| 延迟加载(Lazy Load) | 如 EF Core 的导航属性代理 |
| 缓存 | 先查缓存,没有再调真实对象 |
| 远程调用(RPC) | 本地代理代表远程服务(如 WCF) |
| 测试 Mock | 单元测试中用 Mock 代理替代真实依赖 |
🆚 五、代理 vs 装饰器(Decorator)?
很多人会混淆代理和装饰器,其实:
| 代理(Proxy) | 装饰器(Decorator) | |
|---|---|---|
| 目的 | 控制访问(侧重"管控") | 增强功能(侧重"扩展") |
| 关系 | 通常隐藏真实对象 | 明确组合并暴露增强行为 |
| 透明性 | 客户端通常不知情 | 客户端可能知道被装饰了 |
| 例子 | 权限代理、远程代理 | 给流加缓冲、加密 |
但在代码结构上,两者非常相似,代理可以看作是一种特殊的装饰器。
"代理的大概意思就是生成的这个新类代替原来的类进行一些操作的意思"
更完整地说:
代理是一个与原类具有相同接口(或继承关系)的新类,它"代替"原类接收调用,并在适当时机决定是否、何时、如何调用原类的方法,同时可插入额外逻辑。
而现代框架(如 ASP.NET Core 的 DI、Entity Framework、Castle、Autofac)大量使用动态代理来实现 AOP、懒加载、事务管理等,而你作为开发者几乎无需关心底层生成过程。
如果你正在用类似 Castle 或 .NET 的拦截机制,现在你应该明白:
那个"看不见的代理类",就是你真实服务的"替身保镖" 👮♂️✨