代理模式是什么?如何在 C# 中实现代理模式

简介:

代理模式是什么?如何在 C# 中实现代理模式

代理模式 并不是日常开发工作中常常用到的一种设计模式,也是一种不易被理解的一种设计模式。但是它会广泛的应用在系统框架、业务框架中。

定义
它的 定义 就如其它同大部分 设计模式 的定义类似,即不通俗也不易懂,而且随便百度一下就能找到 : 为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。

每个字都认识,连在一起就看不懂了 by. 某个攻城狮

我们一个词一个词看就明白了。

其他对象
所谓的 其它,其实就是你系统中 任意 一个类型,可以是 UserService、OrderRepository、DataDeletedEventListener、等等。

控制对这个对象的访问
访问 其实就是调用这个对象上的方法、访问它的属性、设置它的属性等等,比如

User user = UserService.GetUserById(1); // 访问了 GetUserById 方法
int id = user.Id; // 访问了 Id 属性
Order order = OrderRepository.SelectByUserId(id); // 访问了 SelectByUserId 方法
控制访问 ,控制 的本质是包装,外部不再直接使用 其他对象 ,而是使用 代理 ,再由代理来访问 其它对象。我们可以使用一个已有的 List 实现一个 IList ,并在使用 Add 方法时,打印一行日志。

public class LogList : IList
{
// other code here..

private IList raw; // 这个就 "其它对象"

public EventList(IList raw)
{

  this.raw = raw; // 通过构造函数,这可以让 EventList 控制对 IList<T> 的访问。

}

public void Add(T value)
{

  this.raw.Add(value);
  Console.WriteLine(value);

}
}
上面就是一个简单的代理模式的例子:
为 IList 提供一种 LogList ,以控制对 IList 的访问。

实现
简单实现
上面 LogList 就是一种简单的实现。

但是你无法对这个类做外部扩展,所有的逻辑都在类型的内部被固定了。

于是我们可以使用下面的方法创建一个可以灵活扩展的 ListProxy

public interface IListInterruption
{

// other codes

// 执行 IList.Add 时会进入的方法
void OnAdding(IList<T> list, T addingValue);

// 执行完 IList.Add 时会进入的方法
void OnAdded(IList<T> list, T addedValue);

// other codes

}

// 列表代理类
// 允许外部提供 IListInterruption 来丰富 ListProxy 的逻辑。
public class ListProxy : IList
{

private readonly IList<T> raw;
private readonly List<IListInterruption> interruptions;

public ListProxy(IList<T> raw)
{
    this.interruptions = new List<IListInterruption>();
    this.raw = raw;
}

public void AddInterruption(IListInterruption interruption)
{
    this.interruptions.Add(interruption);
}

public void Add(T value)
{
    foreach(var item in this.interruptions)
        item.OnAdding(this.raw, value);

    this.raw.Add(value);
    
    foreach(var item in this.interruptions)
        item.OnAdded(this.raw, value);
}

}
上面的代码实现一个较为灵活的 ProxyList 。

首先看看 IListInterruption。通过实现 IListInterruption 接口,可以向 ProxyList 提供各种各样的功能。

我们可以看一个简单的功能

public class LogListInterruption : IListInterruption
{

// other codes

public void OnAdding(IList<T> list, T addingValue)
{
    Console.WriteLie("Adding : {0}", addingValue);
}

// other codes

}
向 ProxyList 添加上述组件,就可以实现在 Add 前打印待添加的值的功能。

List myList = new List();
ProxyList proxy = new ProxyList(myList);
proxy.AddInterruption(new LogListInterruption());
proxy.Add(1);
// >> Adding : 1
这种实现方式可以创建出针对某个类型的代理类,并通过外部给予的 IListInterruption 来丰富代理类功能。

但缺点是,当你无法为所有的类型都创建 Proxy 和 Interruption 。

动态代理类
之前的方法中,我们在编写阶段就已经建立了代理类,被称为静态代理类。

这种方法无法将代理类运用在系统中任何一个我们可能需要的类型上。

于是,动态代理类 就来了。

动态代理类 依靠编程语言本身的特征,让程序在 运行时 创建类型,实现接口,添加功能等等。

在 C# 中可以通过两种方式实现运行时创建类型的功能

CodeDom + 运行时编译
Emit
CodeDom 可以用来生成 C# 代码,再利运行时编译,会将C#代码编译为内存中的程序集,最后通过反射访问程序集中的成员。
这种方法的特点就是慢。。。。因为要生成语句,还要编译,生成程序集,最后还要反射,都是大开销,所以慢是可想而知的。

Emit 提供了利用 IL 命令在运行时创建类型、方法,并填充方法内的功能。
毕竟 C# 最终就是编译成 IL 的,所以直接使用 IL 性能当然快无敌了。

这个方式的缺点只有一个 : 学习 IL 。这玩意可不是每个人都愿意去学的。。。

于是,选择一些已经利用 Emit 做好了动态代理类功能的第三方功能库,成为了一个很好的选择。

C# 大环境下,可以用来生成动态代理类的库一般有两个选择 :

PostSharp
Caslte.DynamicProxy
其中 PostSharp 使用了更复杂的技术,不是使用 Emit,而且在编译时,就将代理类所附加的功能放进了目标类型中,你可以通过 Attribute 向任意的方法添加额外的功能。

PostSharp 会在程序编译时,把这些 Attribute 的功能直接编译到方法内部。
这种在编译时就把一切准备好的方法,让 PostSharp 有着最高的运行性能。
但是又傻瓜、又好用的 PostSharp 只有一个缺点 ———— 收费。

Castle.DynamicProxy 是免费的,他是利用 Emit 在程序运行时创建代理类的。
使用 Castle.DynamicProxy 有两个步骤:

编写 Interceptor
将 Interceptor 附加到某个类型或接口上,并得到一个会调用你的 Interceptor 的代理类实例
开发流程很像之前的 LogList 的例子。

相比较 PostSharp 那种一个 Attribute 就搞定一切的模式, Caslte.DynamicProxy 就没有那么方便了。

那么一个显而易见的问题就来了 :
能不能利用 Caslte.DynamicProxy 实现像 PostSharp 那样利用 Attribute 创建代理类的功能呢?

Reface.AppStarter.Proxy
这是基于 Reface.AppStarter 开发的一个功能模块,
使用它,可以利用 Attribute 的方式轻松的创建代理类,并实现 AOP 的功能。

你所要做的,就是创建一个继承于 ProxyAttribute 的特征。

ProxyAttribute 中有三个方法需要重写

OnExecuting ,被标记的方法执行时
OnExecuted ,被标记的方法执行后
OnExecuteError , 被标记的方法执行出现异常后
你可以编写你的逻辑在这三个方法内,并将你的 Attribute 挂载到你需要的类型的方法上即可。

剩下的事情只有两件

向你的 AppModule 添加 ProxyAppModule
为你需要创建代理的类型加上 [Component] 特征
你已经完成了所有工作,
当你利用 Reface.AppStarter 的框架的 IOC / DI 容器创建你的类型时,实际得到的就是代理类,这些代理类会调试你给予的 ProxyAttribute 。

关于 Reface.AppStarter.Proxy 的细节,会在以后的文章中进一步介绍。

相关文章
|
26天前
|
设计模式 缓存 C#
C# 一分钟浅谈:装饰者模式与代理模式
【10月更文挑战第12天】本文介绍了面向对象编程中的两种常见设计模式:装饰者模式和代理模式。装饰者模式允许在运行时动态地给对象添加功能,而代理模式则通过代理对象控制对另一个对象的访问。文章详细讲解了这两种模式的概念、常见问题、如何避免问题以及代码示例,帮助读者更好地理解和应用这些设计模式。
35 13
|
网络安全 C#
C#设计模式之十二代理模式(Proxy Pattern)【结构型】
原文:C#设计模式之十二代理模式(Proxy Pattern)【结构型】 一、引言   今天我们要讲【结构型】设计模式的第七个模式,也是“结构型”设计模式中的最后一个模式,该模式是【代理模式】,英文名称是:Proxy Pattern。
1801 0
|
SQL C# 设计模式
乐在其中设计模式(C#) - 代理模式(Proxy Pattern)
原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern)[索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为其他对象提供一个代理以控制对这个对象的访问。
973 0
|
C# 设计模式 iOS开发
C#设计模式(13)——代理模式(Proxy Pattern)
原文:C#设计模式(13)——代理模式(Proxy Pattern) 一、引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代理对象代替目标对象,然后客户端只需要访问代理对象,由代理对象去帮我们去请求目标对象并返回结果给客户端,这样的一个解决思路就是今天要介绍的代理模式。
1133 0
【读书笔记】代理模式代码(C#)
  代理模式代码,与大家分享,代码如下:/Files/cappuccino/ProxyModel.rar
689 0
|
6月前
|
开发框架 前端开发 .NET
C#编程与Web开发
【4月更文挑战第21天】本文探讨了C#在Web开发中的应用,包括使用ASP.NET框架、MVC模式、Web API和Entity Framework。C#作为.NET框架的主要语言,结合这些工具,能创建动态、高效的Web应用。实际案例涉及企业级应用、电子商务和社交媒体平台。尽管面临竞争和挑战,但C#在Web开发领域的前景将持续拓展。
190 3
|
11天前
|
C# 开发者
C# 一分钟浅谈:Code Contracts 与契约编程
【10月更文挑战第26天】本文介绍了 C# 中的 Code Contracts,这是一个强大的工具,用于通过契约编程增强代码的健壮性和可维护性。文章从基本概念入手,详细讲解了前置条件、后置条件和对象不变量的使用方法,并通过具体代码示例进行了说明。同时,文章还探讨了常见的问题和易错点,如忘记启用静态检查、过度依赖契约和性能影响,并提供了相应的解决建议。希望读者能通过本文更好地理解和应用 Code Contracts。
24 3
|
1月前
|
安全 C# 数据安全/隐私保护
实现C#编程文件夹加锁保护
【10月更文挑战第16天】本文介绍了两种用 C# 实现文件夹保护的方法:一是通过设置文件系统权限,阻止普通用户访问;二是使用加密技术,对文件夹中的文件进行加密,防止未授权访问。提供了示例代码和使用方法,适用于不同安全需求的场景。