当我会AOP之后,去丈母娘家都是挺着胸脯!

 

图片

 

当和朋友谈到AOP时,第一映像会说AOP的应用层面,比如拦截器、过滤器,实现复用等等使用层面上。

 

这些应用层面上的回答远远没有深入AOP的思想。是的,AOP是思想,面向切面思想。

 

既然是编程思想,那我们就有必要了解AOP的整个过程,以及AOP思想出现的原因。

图片

 

AOP面向切面编程思想,能够解决什么问题,我们回顾一下编程思想的发展路线......

 

早期的POP面向过程编程即是以功能为中心来进行思考和组织的一种编程方法,强调的是功能

 

分析解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时按顺序依次调用,严格按照顺序,侧重解决步骤,着眼局部或具体。

 

实际是一种单一的思考方式,符合人类的思考方式,是一种基础的方法,从实际出发。

 

它能够流程化编程任务,只需要考虑实现方式和最终结果;开发效率高,代码短小精悍,善于结合数据结构来开发高效率的程序;明确流程,步骤清楚,便于节点分析。

 

但是,需要深入思考,比较耗费精力;代码复用性低,不易扩展,维护难度大,且面向过程的模块化难度较高,耦合度也高。

 

由此可见,随着时代发展,面对的系统逐渐复杂,一般的POP无法满足,于是出现了OOP面向对象编程思想。

 

需要说明的是,并不是因为OOP的出现,才使得POP没有余地,或许有不少的伙伴甚至没听过POP。POP和OOP其实是一种互补关系,相关复杂问题拆解之后还是会回归到面向过程的思想。

 

OOP,面向对象编程,以对象为中心,复杂系统出现时,盛行的一种新型的程序设计思想。以对象模型为基础进行的抽象过程,并在应用过程中描述自己的抽象概念定义,包括对象、类、封装、继承等语法和概念。

 

通常脱口而出“万物皆对象”,它可以搭建大型的复杂的系统,它是将数据抽象为模块结构,然后必须存在某种方式来实现代码的多态执行,最后它能压缩部分代码和函数。

 

或许不是很好理解。

 

举个例子,比如说:我们的系统是一个建筑,那类/对象就是砖块,砖块能够组成墙,墙能构成房间,房间组合在一起就组成了一栋建筑。

 

图片

 

这是不是和我们面向对象编程时是一样的?一个模块由多个类共同实现,模块又组成了某项服务,多个服务构成了一个完整的系统。

 

那么,POP能够满足精简系统的开发,OOP能够满足复杂的系统,为什么还会出现AOP呢?

 

首先,构建了一个系统之后,依然会有需求的存在,有了需求就会难免调整代码,那么类就会发生变化,如果大规模变化将是不现实的,整个系统就会存在隐患以及人力物力的多余需求。

 

类应该是固定的,不应该频繁更改,之所以出现了那么多的设计原则和设计模式,目的就是针对不断的需求变化而进行拆解分离,使我们的类能够像砖块一样固定,从而让系统稳健。

 

我们设计完一个系统之后,新增需求要增加一个日志打印模块,授权模块,如果在各个模块都添加的话改动的工作量无疑是很大的,存在的隐患也是很大的。

 

从对象的组织角度来讲,类是继承关系,适合纵向扩展,这也是OOP的思想。

 

就像我们的建筑,打好地基稳固之后,纵向增加楼层是相对较方便的,但是横向扩展是很困难的。

 

因此,面向对象设计有两个缺陷:

 

1.共性问题,面向对象设计一般是纵向思维,总会有一些共性不足。

 

2.扩展问题,当我们需要对现有的对象动态的新增某些行为或责任时就会变得比较困难。

 

于是,AOP出现了,来弥补OOP的共性问题和扩展问题。

 

当然,AOP不是OOP的升级版,是对OOP缺陷的补充

 

POP,OOP,AOP 这三种编程方式,本质也是互相弥补,从来不是哪个盛行而其他的就需要了。

那么到底什么是AOP呢?

 

AOP面向切面编程,切面就是横切关注点模块化,OOP是使用类状态(属性)和行为模块化。

 

类和接口组织的,是针对横向关注点,跨越应用程序的多个模块的功能需求。

 

AOP涉及的应用,例如:日志记录、性能统计、安全控制,异常处理。都是可以从业务代码中划分出来,非业务逻辑的方法。

 

AOP善于将公共的功能提取出来,成立公共的模块,只关注通用的功能,不关注业务逻辑。

 

AOP的优势:

 

1.将通用的功能从业务逻辑中抽离出来,提高代码的复用性,有利于后期的维护和扩展。

 

2.在软件设计时,抽出通用功能,有利于软件设计的模块化,降低架构的复杂度。

 

AOP与 OOP所针对的目标是不同的。OOP针对业务处理过程的实体、属性,行为进行抽象封装。

 

AOP则是针对业务处理过程中切面进行提取,就是面向对象过程中的某个步骤或阶段的提取,来降低逻辑过程中各个部分的耦合。

 

因此,相比于OOP,可以总结出AOP的特点。

 

1.面向目标不同,OOP面向名词,AOP面向动词。

 

2.思想结构不同,OOP是纵向,AOP是横向。

 

3.注重方面不同,OOP偏重业务逻辑单元划分,AOP偏重业务处理过程中的某个步骤。


那么,我们在AOP应用层面的实现,有两种常见的方式。

 

  1. 静态代理AOP,就是手写代码。

 

我们以装饰器模式为例子,装饰器就是在一个原有对象的情况下封装一个新的装饰器类,来包装原有类,提供额外的功能。

 

//接口服务
public interface ITravelService
{
  Task PlanToTravel(Travel travel);
}
public class TravelService : ITravelService
{
   public Task PlanToTravel(Travel travel)
   {
      Console.WriteLine($"旅客{travel.name}成功加入旅行团");
      return Task.CompletedTask;
    }
}

 

//装饰器
public class TravelDecorator : ITravelService
{
  private readonly ITravelService _travelService;

  public TravelDecorator(ITravelService travelService)
  {
    _travelService = travelService;
  }

  public async Task PlanToTravel(Travel travel)
  {
    //旅行前
    await IsAllowToTravel(travel);
    await _travelService.PlanToTravel(travel);
    //旅行后
    await IsAllowBack(travel);
  }
  public Task IsAllowToTravel(Travel travel)
  {
    Console.WriteLine($"目前处于疫情严重,将停止旅游!");
    return Task.CompletedTask;
  }
  public Task IsAllowBack(Travel travel)
  {
    Console.WriteLine($"返回目标地处于风控期,暂时无法返航!");
    return Task.CompletedTask;
  }

 

2.动态代理实现,可以通过反射来实现。

 

例如现有的AOP框架,Romoting(分布式通讯框架)、Castle轻量级容器(包含实现ORM、IOC、MVC,AOP)、Unity(IOC容器,AOP)。

 

以 Remoting和Castle 分别写一个实例,如下:

 

//Remoting 例子
public class DynamicProxy<T> : DispatchProxy where T : class
{
  public T Target { get; set; }
  public DynamicProxy(){}
  //执行之前执行逻辑
  public Action BeforAction { get; set; }
  //执行之后执行逻辑
  public Action AfterAction { get; set; }

  public static T Decorate(T target, Action BeforAction, Action AfterAction)
  {
    // DispatchProxy.Create creates proxy objects
    var proxy = Create<T, DynamicProxy<T>>() as DynamicProxy<T>;
    proxy.AfterAction = AfterAction;
    proxy.BeforAction = BeforAction;

    // If the proxy wraps an underlying object, it must be supplied after creating the proxy.
    proxy.Target = target ?? Activator.CreateInstance<T>();
    return proxy as T;
  }
  protected override object Invoke(MethodInfo targetMethod, object[] args)
  {
    //执行业务之前的代码逻辑
    BeforAction();
    var result = targetMethod.Invoke(Target, args);
    //执行业务之后的代码逻辑
    AfterAction();
    return result;
        }
    }
//remoting 实例 使用方式
var tralvel = new Travel
    {
       name = "张三",
       date = DateTime.Now,
       telphone = "110",
       travel_target = "HangZhou"
     };
     
var service = new TravelService();
var proxyService = DynamicProxy<ITravelService>.Decorate(service,
          () => { Console.WriteLine("执行逻辑前"); },
          () => { Console.WriteLine("执行逻辑后"); });

proxyService.PlanToTravel(tralvel);

 

//castle 实例 
public class CastleProxy<T> : IInterceptor where T : class
{
  private static readonly ProxyGenerator _generator = new ProxyGenerator();
  public T Target { get; set; }
  public CastleProxy(){}
  //执行之前
  public Action BeforAction { get; set; }
  //执行之后
  public Action AfterAction { get; set; }
  public static T Decorate(T target, Action BeforActions, Action AfterActions)
  {
    var proxy = target != null ?
        _generator.CreateInterfaceProxyWithTarget(target, new CastleProxy<T>() 
          {
             BeforAction = BeforActions,
             AfterAction = AfterActions 
           }):
         _generator.CreateInterfaceProxyWithTarget<T>(Activator.CreateInstance(typeof(T)) as T,new CastleProxy<T>()
          {
             BeforAction = BeforActions,
             AfterAction = AfterActions
          });
    
    return proxy;
  }
  public void Intercept(IInvocation invocation)
  {
    try
       {
        BeforAction();
        invocation.Proceed();//程序执行
        AfterAction();
       }
       catch (TargetInvocationException error)
       {
        throw error.InnerException;
       }
  }
}
//castle 实例 使用方式
var tralvel = new Travel
    {
       name = "张三",
       date = DateTime.Now,
       telphone = "110",
       travel_target = "HangZhou"
     };
     
var service = new TravelService();
var proxyService = CastleProxy<ITravelService>.Decorate(service,
          () => { Console.WriteLine("执行逻辑前"); },
          () => { Console.WriteLine("执行逻辑后"); });

proxyService.PlanToTravel(tralvel);

 

好了,以上就是AOP面向切面编程思想的内容了,希望我讲解的内容能够帮到大家。哈,希望伙伴们给个小心心!

 

posted @ 2022-05-16 21:16  桑小榆呀  阅读(150)  评论(2编辑  收藏  举报