和往常同样,小吴最后一个来到工位上,用脚点开主机的按钮,伴随着主机箱里传出的卡车启动般的轰轰声,一天的快乐摸鱼时光又开始了......编程
点开腾讯体育新闻,小吴正准备看看昨晚NBA的战况如何。忽然,小吴的耳朵一阵警觉,似曾相识的脚步声愈来愈近,,,小吴心想:难道,我上班摸鱼被老板发现了??,,关掉手机正在播放的NBA精彩十佳球,小吴若无其事地缓缓抬起头,把目光挪向眼前的电脑屏幕,眉间一皱,左手键盘,右手鼠标,毫无破绽,俨然一副认真搬砖的样子。c#
脚步声随即不出所料的停在小吴的跟前,抬头一瞧,原来是项目经理大勇,小吴明白这是来活了。设计模式
“小吴,客户有个新需求,XX项目客户须要记录每个业务操做的时间和操做人信息,你来作一下这个功能吧,客户但愿明天就能上线这个功能。”框架
“哦。。哦。。。好的。”,小吴知道今天注定不会是快乐摸鱼的一天,可是为了尽快能摸上鱼,小吴快速的打开了XX项目,开始分析需求......ide
项目的原始业务代码是这样的:函数
1 //业务类接口 2 public interface IBLLClass 3 { 4 void DoThing1(); 5 void DoThing2(); 6 } 7 8 //业务类 9 public class BLLClass : IBLLClass 10 { 11 public void DoThing1() 12 { 13 //DoThing1的业务逻辑 14 Console.WriteLine("执行DoThing1..."); 15 } 16 17 public void DoThing2() 18 { 19 //DoThing2的业务逻辑 20 Console.WriteLine("执行DoThing2..."); 21 } 22 23 }
若是是一年前的小吴看到这样的代码,二话不说,他会直接往业务类中硬生生地插入要增长的功能,就像这样:学习
1 //业务类 2 public class BLLClass : IBLLClass 3 { 4 public void DoThing1() 5 { 6 LogUserOperation(); 7 8 //DoThing1的业务逻辑 9 } 10 11 public void DoThing2() 12 { 13 LogUserOperation(); 14 15 //DoThing2的业务逻辑 16 } 17 18 private void LogUserOperation() 19 { 20 //记录每个业务操做的时间和操做人信息 21 } 22 }
可是,这时的小吴脑子里想到的是他在某一本讲设计模式的书上看到的那句话:尽可能避免编写对原系统代码侵入性强的代码。spa
何谓侵入性强的代码,以上的代码就是一个很好的例子:它直接将须要新增的业务代码插入到原来的业务代码中。这就带来了一个问题,若是你是用这种方法频繁地去扩展你的业务代码,那么过不了多久,你就很难再理清你原来最基本的业务逻辑是什么样的了,到最后会发现本身的代码面目全非。设计
因此,懒惰又聪明地小吴很快就想起了前不久在书上看到的代理模式,说时迟,那时快,小吴在键盘上“咔咔咔”一顿骚操做,以迅雷不及掩耳之势敲完了代码,哼,单身22年的手速可不是盖的,你懂得,嘿嘿嘿。。。额。。跑题了。。。我们回头来看看小吴写的代码有多骚:3d
1 //业务代理类 2 public class BLLClassProxy : IBLLClass 3 { 4 private IBLLClass bllClass = new BLLClass(); 5 6 public void DoThing1() 7 { 8 //添加的业务逻辑 9 LogUserOperation(); 10 11 //调用原始逻辑 12 bllClass.DoThing1(); 13 } 14 15 public void DoThing2() 16 { 17 LogUserOperation(); 18 19 bllClass.DoThing2(); 20 } 21 22 private void LogUserOperation() 23 { 24 //记录每个业务操做的时间和操做人信息 25 } 26 }
若是你认真看过上面的代码就会明白,BLLClassProxy这个类实现了BLLClass中所具有的全部业务函数,并且最终的业务逻辑都是来自对BLLClass类中业务函数的调用,BLLClassProxy类彻底能够代替BLLClass类,并且在BLLClassProxy中还能够任意增长额外的业务逻辑,这很好的实现了咱们须要的效果:对原始代码没有侵入性,且达到扩展业务逻辑的目的。咱们把BLLClassProxy称做为BLLClass的代理类,顾名思义,前者代理了后者全部的业务逻辑,故称之为代理类。
那么咱们将会在实际的调用代码中作以下改动:
1 IBLLClass bll = new BLLClass(); //==> 修改前:使用原始业务类 2 3 IBLLClass bll = new BLLClassProxy(); //==> 修改后:使用代理业务类
咱们看到,因为原始业务类(BLLClass)与代理业务类(BLLClassProxy)都实现了接口IBLLClass,因此只须要将业务类声明变量切换成代理类的实现就完成了整个需求的变更,无需作其余改动。固然,这还要得益于业务类的建立者的先见之明,提供了一个业务类的接口(IBLLClass),这也同时给咱们提了个醒,尽可能以接口的方式声明业务类变量,就是所谓的“面向接口编程”。
以上就是使用了代理模式来解决业务扩展的需求,其实再按细分的话,咱们能够将以上的代理叫作 静态代理。静态代理指的就是在代码编译阶段就已经生成代理类,而你须要在程序运行前就将代理类的代码一五一十地写好,若是有五十个代理类就写五十个,有一百个就写一百个。有人会问,啥?难不成还能有动态代理?固然,继续看剧情发展......
项目经理大勇又一次笑眯眯地走向小吴,小吴不由心头一紧,心想,不妙。
“小吴啊,客户又提了几个需求,不过不用慌,和上次要加的那个需求同样,只不过此次把另外那20个业务类也加上一样的业务逻辑。”
小吴心中即使一万个草泥马,可是却依然面带微笑,点头“好好好”。
大勇也不忘夸小吴两句:“上回加的那个代理类很不错嘛,就照着那种方法加,很快的”。
“很快?要不你来试试?”,小吴一边嘴里嘀咕着,一边在脑子里又蹦出了个新想法。
又要手撸20多个代理类?有没有什么别的方法能减小个人工做量呢,好比。。。自动生成代理类?
年轻人就怕没想法,有想法就要付诸于行动,因而小吴开始寻思着如何实现本身想法。
自动生成代理类?从解决问题的思路出发有两种解决方法:
一、写一个代码生成器,生成代理类的代码,而后再进行编译。这种方法本质上仍是咱们上面介绍的静态代理类,只不过不用咱们手动编写代理类的代码,可是使用这种方法是极其痛苦的,虽然你不用手动编写真正的代理类代码,可是你必须去作一些代码生成的配置吧,这个过程是及其繁琐的,一个字归纳,“太他妈LOW了!”
二、在程序编译好后跑起来的过程当中,动态生成代理类。说的是什么?程序都已经跑起来了还能生成代理类?不错,这就是动态生成代理类,借助的是c#语言的Emit高级特性。
显然咱们须要的是动态生成代理类,那么这么说的话咱们还必需要再学一学Emit建立类?小吴以为照这样下去这事儿得黄了,这已经不是临阵磨枪了,这是要临阵造轮子啊,这活还干不干了,等着造完这个轮子,黄花菜都凉了。
因而当天晚上祖师爷就托梦给小吴,让小吴用一用 Castle 框架,如获至宝的小吴次日就按照祖师爷的指示用上了Castle框架,嗯,真香~~
咱们在使用技术中大部分都是用既有的轮子,造轮子这种事情让小吴干,小吴可不乐意。固然,造轮子对于咱们的学习仍是颇有用处的,尝试着去造造轮子,会提高你对技术更深层次的理解,由于你再也不只是站在使用者的角度简单地看问题。
咱们来看看Castle是怎么使用的:
一、首先引用 Castle.Core 的dll文件
二、建立建拦截器,拦截器的意思很是直观,就是把运行着的方法拦下来,等会儿,你先别运行,先执行完我给你的方法A,再运行你本身的方法,而后再运行我给你的方法B......也就是说经过拦截器你能够在原始业务逻辑的先后或者任意可切入的点插入你想加入的业务逻辑。Castle 框架提供了一个标准的拦截器类 StandardInterceptor:
1 public class StandardInterceptor : MarshalByRefObject, IInterceptor 2 { 3 public StandardInterceptor(); 4 5 public void Intercept(IInvocation invocation); 6 protected virtual void PerformProceed(IInvocation invocation); 7 protected virtual void PostProceed(IInvocation invocation); 8 protected virtual void PreProceed(IInvocation invocation); 9 }
你能够重写 PreProceed、PerformProceed、PostProceed 三个虚方法,它们表示三个拦截点:执行前、执行中、执行后,你能够加入本身的业务逻辑到这三个拦截点里,实现业务的添加。
因而像这样创建一个拦截器类:
1 public class LogInterceptor: StandardInterceptor 2 { 3 protected override void PostProceed(IInvocation invocation) 4 { 5 LogUserOperation(); 6 } 7 8 private void LogUserOperation() 9 { 10 //记录每个业务操做的时间和操做人信息 11 Console.WriteLine("记录日志"); 12 } 13 }
而后这样编写建立业务类变量的代码:
1 //代理生成类 2 ProxyGenerator proxyCreator = new ProxyGenerator(); 3 4 //经过Castle动态生成代理类 5 IBLLClass bll = proxyCreator.CreateInterfaceProxyWithTargetInterface<IBLLClass>(new BLLClass(), new LogInterceptor());
咱们能够看到最终业务类实例的建立是借助于Castle框架来生成的,其实Castle框架就替咱们完成了动态代理类的生成,咱们只须要在拦截器中写好咱们须要加入的拦截方法体代码,而后注入到代理类。固然这里只是提供了使用Castle框架一个很简单的例子,其实Castle中还有不少丰富的功能,有待各位看官根据本身的需求去发掘,师傅领进门,修行靠我的嘛,就是这么个道理。最后展现一下运行结果:
动态代理能够称的上是代理模式的最高境界,由于它借助动态生成的技术让程序在运行过程当中自动根据注册条件生成代理类,省去了手写静态代理类的麻烦。同时动态代理模式也是AOP(面向切面编程)的一种很好的实现方式。