C# 代理模式

代理(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 的拦截机制,现在你应该明白:

那个"看不见的代理类",就是你真实服务的"替身保镖" 👮‍♂️✨

相关推荐
shmily麻瓜小菜鸡11 分钟前
JS/TS 易踩坑知识点 — 模块化与工程化类
开发语言·javascript·ecmascript
geovindu23 分钟前
CSharp: Observer Pattern
开发语言·后端·观察者模式·设计模式·c#·.netcore·行为模式
郝学胜-神的一滴1 小时前
C++11 工程级应用 09:告别无谓拷贝,解锁高性能移动语义
开发语言·数据结构·c++·vscode·软件工程·visual studio
MC皮蛋侠客2 小时前
OPC UA 系列(一):标准全景与 Python 最小闭环——让第一条设备数据流动起来
开发语言·python·opcua
SamChan902 小时前
PDF翻译后的格式完整性校验:用Python自动比对译文与原文档的表格与段落结构
开发语言·python·ai·pdf·机器翻译
君顾13 小时前
外卖CPS系统开发实战指南:从架构设计到部署全流程解析
java·开发语言·外卖
是立不是利3 小时前
前端交互基石:深入剖析JavaScript三级联动背后的设计哲学
开发语言·前端·javascript
老刘的望远镜3 小时前
AgentScope Java 从零(03):Agent 的记性默认全开,我在第 50 轮翻了车
java·开发语言·javascript
Littlehero_1214 小时前
QT自定义控件之电气接线图(源码开源)
开发语言·qt