代理模式的代理和现实生活中的“代理”其实是差不多的。 比如我们通过火车票代售点买票, 那代售点就是一种对售卖火车票代理; 一个代理商帮忙卖一个厂家的或,从中赚取利润,这个代理商也是一种代理。。这样的“代理”的例子很多,也看得出来,代理他不会对原有功能,或者说是业务逻辑有什么影响,但是代理操作可以具有额外的动作,比如代理商卖被代理厂家的产品的时候,他可以通过对这个产品再进行精美的包装,获得更好的利润,那这个包装动作就是一种除真实业务逻辑之外的额外的操作。 在程序当中来说, 我们使用代理,也是为了在调用原有方法的同时, 在真实调用方法的前后增加一些操作。
根据代理的目的的不同,代理一般分为:
- 远程代理:隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如Nginx转发。
- 虚拟代理:这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
- 安全代理:这种方式通常用于控制不同客户端对真实对象的访问权限。
- 智能指引:主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。
- 延迟加载:指为了提高系统的性能,延迟对目标的加载
根据实现方式的不同,代理模式可以分为:
- 静态代理
- 动态代理
1、场景描述
我们有一个已经实现的付款功能,现在我们需要在不改变这个类、方法的前提下,增加权限验证和日志记录的功能,使用代理模式来实现。
2、实现
// 支付主题抽象 (ISubject)public interface IPayment{/// <summary>/// 支付/// </summary>void Pay();}/// <summary>/// 微信支付 -- 具体实现(subject)/// </summary>public class WeiXinPayment : IPayment{public void Pay(){Console.WriteLine("微信支付");}}/// <summary>/// 支付代理 -- 代理(proxy)/// </summary>public class WeiXinPaymentProxy : IPayment{private WeiXinPayment weiXin = new WeiXinPayment();/// <summary>/// 权限验证/// </summary>public void Authorize(){Console.WriteLine("验证成功");}public void Pay(){this.Authorize();weiXin.Pay();this.Log();}/// <summary>/// 日志记录/// </summary>public void Log(){Console.WriteLine("记录日志:支付成功");}}// 客户端调用// 之前的微信支付IPayment payment = new WeiXinPayment();payment.Pay();Console.WriteLine("********************");// 代理模式下的微信支付IPayment proxy = new WeiXinPaymentProxy();proxy.Pay();
上面的例子只是简单的来说明代理模式的使用,通过上面的实例我们知道,代理模式的作用可以理解为 代码增强。也就是不破坏原有封装的情况下加逻辑。除此之外,当我们希望具体的调用类及方法不想让客户端得知时,也可以使用代理模式,这叫 代码保护。
3、优缺点
优点:
- 可以对原有功能起到一个保护或者增强的作用
- 符合开闭原则,不破坏原有封装
- 在一定程度上还有解耦的作用
缺点:
- 会使类数量增加(考虑使用动态代理)
- 增加维护成本
4、应用场景
在代码编写的过程中,所有需要在不破坏原有逻辑封装的前提下增强和隐藏原有逻辑的需求,都可以考虑使用代理模式,比如AOP本身一种代理的实现。如何调用对象的某一功能是重点考虑的,不需要兼顾所有的功能。核心是代理原有对象的功能来完成某一流程。
值得注意到是:
代理模式注重对对象某一功能的流程把控和辅助,不需要去兼顾原对象的所有功能,就像我作为一个代理商,我不需要去关心原商家的产品的制作流程或者别的什么的,我只是拿到这件产品好好的代理卖出去即可。代理模式可以控制对象做某些事,重心是为了借用对象的功能完成某一流程,而非对象功能如何,代理后的对象不一定是原对象了。这也是它和装饰器设计模式的一方面的区别。
