Aspect-Oriented Programming-Aop 概念 优势 开票演示 静态代理 动态代理

AOP面向切面的编程,它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是通过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。但是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,比如日志记录,权限验证,异常拦截等。

优势

  • 将通用功能从业务逻辑中抽离出来,可以省略大量重复代码,有利于代码的操作和维护。
  • 在软件设计时,抽出通用功能(切面),有利于软件设计的模块化,降低软件架构的复杂度。也就是说通用的功能都是一个单独的模块,在项目的主业务里面是看不到这些通用功能的设计代码的。

开票演示

这里首先有个开票服务类,里面有个开票方法,会记录日志,也就是记录传入的dto信息,很明显这里违反了 单一职责原则,如果有多个方法 都要记录日志,日后万一需求变更,要记录多个参数呢?每个方法都要修改,很显然是不行的。

    public interface IInvoiceService
    {
        void Invoice(string invoiceDto);
    }
    public class InvoiceService : IInvoiceService
    {
        public  void Invoice(string invoiceDto)
        {
            Console.WriteLine("记录日志" + invoiceDto);
            Console.WriteLine("开电子票ing");
        }
    }

静态代理

又叫编译时代理,就是在编译的时候,已经存在代理类,运行时直接调用的方式。说的通俗一点,就是自己手动写代码实现代理类的方式。

    class InvoiceProxyService
    {
        IInvoiceService invoiceService;
        public InvoiceProxyService(IInvoiceService invoiceService)
        {
            this.invoiceService = new InvoiceService();
        }
        public void Invoice(string invoiceDto)
        {
            Console.WriteLine("记录日志" + invoiceDto);
            invoiceService.Invoice(invoiceDto);
        }
    }

还可以更优雅一些, 就是代理类 继承自我们的实现类

    public class InvoiceService : IInvoiceService
    {
        public virtual void  Invoice(string invoiceDto)
        {
            Console.WriteLine("开电子票ing");
        }
    }

    class InvoiceProxyService:InvoiceService
    {
        public override void Invoice(string invoiceDto)
        {
            Console.WriteLine("记录日志" + invoiceDto);
            base.Invoice(invoiceDto);
        }
    }

动态代理

那么既然有了 静态代理,为什么还需要动态代理呢。

动态代理,又成为运行时代理。在程序运行的过程中,调用了生成代理类的代码,将自动生成业务类的代理类。不需要我们手共编写,极高的提高了工作效率和调整了程序员的心态。

Castle DynamicProxy

首先要定义个拦截器,castle里要实现IInterceptor这个接口

    public class MyInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine("记录日志。。。");
            invocation.Proceed();
        }
    }

然后要保证的是我们服务类必须是虚方法virtual标记的。
使用的话也很简单

var proxyGenerator = new ProxyGenerator();
var p = proxyGenerator.CreateClassProxy<InvoiceService>(new MyInterceptor());
p.Invoice("100");

IInvocation Arguments属性 包含了我们调用时传入的参数