C#编程:AOP编程思想

一、什么是AOP

AOP:Aspect Oriented Programming的缩写,意为面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP思想的延续。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

为什么要学习AOP呢?

AOP的应用场景非常广泛,在一些高级工程师或者架构师的面试过程中,频率出现的比较多。

二、编程思想的发展路线

1、POP

POP:Procedure Oriented Programming的缩写,即面向过程编程,是一种以过程为中心的编程思想。

面向过程是分析出解决问题的步骤,然后用函数或者方法,把这些步骤一步一步的实现,使用的时候在一个一个的一次调用函数或者方法,这就是面向过程编程。最开始的时候都是面向过程编程。面向过程是最为实际的一种思考方式。就算是面向对象编程,里面也是包含有面向过程的编程思想,因为面向过程是一种基础的编程思考方式,它从实际出发来考虑如何实现需求。

POP的不足:面向过程编程,只能处理一些简单的问题,无法处理一些复杂的问题。如果问题很复杂,全部以流程来思考的话,会发现流程很混乱,甚至流程都不能进行下去。

2、OOP

OOP:Object Oriented Programming的缩写,即面向对象编程。

早期的计算机编程都是面向过程的,因为早期的编程都比较简单。但是随着时间的发展,需求处理的问题越来越多,问题就会越来越复杂,这时就不能简单的使用面向过程的编程了,就出现了面向对象编程。在计算机里面,把所有的东西都想象成一种事物。现实世界中的对象都有一些属性和行为,也就对应计算机中的属性和方法。

面向对象编程就是把构成问题的事物分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

我们以一栋大楼为例来说明OOP的不足。

我们把系统比喻成一栋楼,类或者对象是砖块,砖块组成了一面墙,多面墙构成一间房间,多个房间构成一栋楼。
这就好比一个模块的功能是由多个类实现,模块又组成了某一项服务,多个服务构成了一个完整的系统。一个系统开发完成并不代表就真的完成了,以后肯定会有各种需求的变更出现,需求变更出现以后就要去修改代码,代码都在类里面,这就相当于去修改类。如果是小范围的修改影响还不是很大,如果是大范围的修改,影响就比较大了。即使每次修改都很小,但是如果经常进行修改,影响也会很大。就会造成系统的不稳定。我们得出结论:类应该是固定的,不应该频繁的去修改,甚至是不允许修改。这也是为什么有那么多的设计原则和设计模式。大部分的设计模式都是为了解决这类问题的,即在不修改类的前提下去扩展功能。

OOP的不足:产生新的需求会导致程序代码不断的进行修改,容易造成程序的不稳定。

如果非常了解OOP的话,那么我们应该知道,从对象的组织角度来讲,分类方法都是以继承关系为主线的,我们称为纵向。如果只使用OOP思想的话,会带来两个问题:
1、共性问题。
2、扩展问题,需要对先有类进行扩展时就比较困难了。

OOP与POP的区别:

在对比面向过程的时候,面向对象的方法是把事物最小化为对象,包括属性和方法。当程序的规模比较小的时候,面向过程编程还是有一些优势的,因为这时候程序的流程是比较容易梳理清楚的。以早上去上班为例,过程就是起床、穿衣、刷牙洗脸、去公司。每一步都是按照顺序完成的,我们只需要按照步骤去一步一步的实现里面的方法就行了,最后在依次调用实现的方法即可,这就是面向过程开发。

如果使用面向对象编程,我们就需要抽象出来一个员工类,该员工具有起床、穿衣、刷牙洗脸、去公司的四个方法。但是,最终要实现早上去上班的这个需求的话,还是要按照顺序依次来调用四个方法。最开始的时候,我们是按照面向过程的思想来思考该需求,然后在按照面向对象的思想来抽象出几个方法,最终要实现这个需求,还是要按照面向过程的顺序来实现。

面向对象和面向过程的区别仅仅是在思考问题方式上面的不同。最终你会发现,在你实现这个需求的时候,即使使用了面向对象的思想抽象出来了员工类,但是最后还是要使用面向过程来实现这个需求。

3、AOP

AOP:Aspect Oriented Programming的缩写,即面向切面编程。是对OOP的一种补充,在不修改原始类的情况下,给程序动态添加统一功能的一种技术。

OOP关注的是将需求功能划分为不同的并且相对独立、封装良好的类,依靠继承和多态来定义彼此的关系。AOP能够将通用需求功能从不相关的类中分离出来,很多类共享一个行为,一旦发生变化,不需要去修改很多类,只需要去修改这一个类即可。

AOP中的切面是指什么呢?切面指的是横切关注点。看下面一张图:

OOP是为了将状态和行为进行模块化。上图是一个商场系统,我们使用OOP将该系统纵向分为订单管理、商品管理、库存管理模块。在该系统里面,我们要进行授权验证。像订单、商品、库存都是业务逻辑功能,但是这三个模块都需要一些共有的功能,比如说授权验证、日志记录等。我们不可能在每个模块里面都去写授权验证,而且授权验证也不属于具体的业务,它其实属于功能性模块,并且会横跨多个业务模块。可以看到这里是横向的,这就是所谓的切面。通俗的将,AOP就是将公用的功能给提取出来,如果以后这些公用的功能发生了变化,我们只需要修改这些公用功能的代码即可,其它的地方就不需要去更改了。所谓的切面,就是只关注通用功能,而不关注业务逻辑,而且不修改原有的类。

AOP优势:

  1. 将通用功能从业务逻辑中抽离出来,提高代码复用性,有利于后期的维护和扩展。
  2. 软件设计时,抽出通用功能(切面),有利于软件设计的模块化,降低软件架构的复杂度。

AOP的劣势:

  1. AOP的对OOP思想的一种补充,它无法单独存在。如果说单独使用AOP去设计一套系统是不可能的。在设计系统的时候,如果系统比较简单,那么可以只使用POP或者OOP来设计。如果系统很复杂,就需要使用AOP思想。首先要使用POP来梳理整个业务流程,然后根据POP的流程,去整理类和模块,最后在使用AOP来抽取通用功能。

AOP和OOP的区别:

  1. 面向目标不同:OOP是面向名词领域(抽象出来一个事物,比如学生、员工,这些都是名词)。AOP是面向动词领域(比如鉴权、记录日志,这些都是动作或行为)。
  2. 思想结构不同:OOP是纵向的(以继承为主线,所以是纵向的)。AOP是横向的。
  3. 注重方面不同:OOP是注重业务逻辑单元的划分,AOP偏重业务处理过程中的某个步骤或阶段。

POP、OOP、AOP三种思想是相互补充的。在一个系统的开发过程中,这三种编程思想是不可或缺的。

三、实现AOP

我们在上面讲解了有关AOP的一些理论知识,那么如何在代码里面实现呢?

实现AOP有两种方式:

  1. 静态代理实现。所谓静态代理,就是我们自己来写代理对象。
  2. 动态代理实现。所谓动态代理,就是在程序运行时,去生成一个代理对象。

1、静态代理

实现静态代理需要使用到两种设计模式:装饰器模式和代理模式。

装饰器模式:允许向一个现有的对象添加新的功能,同时又不改变这个现有对象的结构。属于结构型设计模式,它是作为现有类的一种包装。首先会创建一个装饰类,用来包装原有的类,并在保持类的完整性的前提下,提供额外的功能。看下面的例子。

我们首先创建一个User类:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace StaticDemo.Model
{
    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
}

接着我们创建一个账号服务的接口,里面有一个方法,用来注册一个用户:

using StaticDemo.Model;

namespace StaticDemo.Services
{
    /// <summary>
    /// 接口
    /// </summary>
    public interface IAccountService
    {
        /// <summary>
        /// 注册用户
        /// </summary>
        /// <param name="user"></param>
        void Reg(User user);
    }
}

然后创建一个类来实现上面的接口:

using StaticDemo.Model;
using System;

namespace StaticDemo.Services
{
    /// <summary>
    /// 实现IAccountService接口
    /// </summary>
    public class AccountService : IAccountService
    {
        public void Reg(User user)
        {
            // 业务代码 之前 或者之后执行一些其它的逻辑
            Console.WriteLine($"{user.Name}注册成功");
        }
    }
}

我们在创建一个装饰器类:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    /// <summary>
    /// 装饰器类
    /// </summary>
    public class AccountDecorator : IAccountService
    {
        private readonly IAccountService _accountService;

        public AccountDecorator(IAccountService accountService)
        {
            _accountService = accountService;
        }

        public void Reg(User user)
        {
            Before();
            // 这里调用注册的方法,原有类里面的逻辑不会改变
            // 在逻辑前面和后面分别添加其他逻辑
            _accountService.Reg(user);
            After();
        }

        private void Before()
        {
            Console.WriteLine("注册之前的逻辑");
        }

        private void After()
        {
            Console.WriteLine("注册之后的逻辑");
        }
    }
}

我们会发现装饰器类同样实现了IAccountService接口。最后我们在Main方法里面调用:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // 实例化对象
            IAccountService accountService = new AccountService();
            // 实例化装饰器类,并用上面的实例给构造方法传值
            var account = new AccountDecorator(accountService);
            var user = new User { Name = "Rick", Password = "12345678" };
            // 调用装饰器类的注册方法,相当于调用实例化对象的注册方法
            account.Reg(user);

            Console.ReadKey();
        }
    }
}

运行结果:

下面我们在来看看如何使用代理模式实现。

代理模式:即一个类代表另一个类的功能。我们会创建一个代理类,这个代理类和装饰器类基本一样。看一下代码:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    /// <summary>
    /// 代理类
    /// </summary>
    public class ProxyAccount : IAccountService
    {
        private readonly IAccountService _accountService;

        /// <summary>
        /// 构造函数没有参数
        /// 直接在里面创建了AccountService类
        /// </summary>
        public ProxyAccount()
        {
            _accountService = new AccountService();
        }

        public void Reg(User user)
        {
            before();
            _accountService.Reg(user);
            after();
        }

        private void before()
        {
            Console.WriteLine("代理:注册之前的逻辑");
        }

        private void after()
        {
            Console.WriteLine("代理:注册之后的逻辑");
        }
    }
}

Main方法里面调用:

using StaticDemo.Model;
using StaticDemo.Services;
using System;

namespace StaticDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            #region 装饰器模式
            //// 实例化对象
            //IAccountService accountService = new AccountService();
            //// 实例化装饰器类,并用上面的实例给构造方法传值
            //var account = new AccountDecorator(accountService);
            //var user = new User { Name = "Rick", Password = "12345678" };
            //// 调用装饰器类的注册方法,相当于调用实例化对象的注册方法
            //account.Reg(user);
            #endregion

            #region 代理模式
            var account = new ProxyAccount();
            var user = new User { Name = "Tom", Password = "12345678" };
            account.Reg(user);
            #endregion

            Console.ReadKey();
        }
    }
}

运行结果:

可能有的人会发现,装饰器类和代理类很相像,功能也一模一样,仅仅是构造函数不同。那么装饰器模式和代理模式有区别吗?有些东西,形式上看起来区别很小,但实际上他们区别很大。它们在形式上确实一样,不管是装饰器类还是代理类,它们都要实现相同的接口,但是它们在运用的时候还是有区别的。

装饰器模式关注于在一个对象上动态添加方法,而代理模式关注于控制对象的访问。简单来说,使用代理模式,我们的代理类可以隐藏一个类的具体信息。var account = new ProxyAccount();仅看这段代码不看源码,不知道里面代理的是谁。

当使用代理模式的时候,我们常常是在代理类中去创建一个对象的实例: _accountService = new AccountService()。而当我们使用装饰器模式的时候,我们通常是将原始对象作为一个参数传递给装饰器的构造函数。简单来说,在使用装饰器模式的时候,我们可以明确地知道装饰的是谁,而且更重要的是,代理类里面是写死的,在编译的时候就确定了关系。而装饰器是在运行时来确定的。

2、动态代理

动态代理实现也有两种方式;

  1. 通过代码织入的方式。例如PostSharp第三方插件。我们知道.NET程序最终会编译成IL中间语言,在编译程序的时候,PostSharp会动态的去修改IL,在IL里面添加代码,这就是代码织入的方式。
  2. 通过反射的方式实现。通过反射实现的方法非常多,也有很多实现了AOP的框架,例如Unity、MVC过滤器、Autofac等。

我们先来看看如何使用PostSharp实现动态代理。PostSharp是一款收费的第三方插件。

首先新创建一个控制台应用程序,然后创建一个订单业务类:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        public void DoWork()
        {
            Console.WriteLine("执行订单业务");
        }
    }
}

接着在Main方法里面调用:

using System;

namespace PostSharpDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            OrderBusiness order = new OrderBusiness();
            // 调用方法
            order.DoWork();
            Console.ReadKey();
        }
    }
}

运行结果:

这时又提出了一个新的需求,要去添加一个日志功能,记录业务的执行情况,按照以前的办法,需要定义一个日志帮助类:

using System;
using System.IO;

namespace PostSharpDemo
{
    public class LgoHelper
    {
        public static void RecoreLog(string message)
        {
            string strPath = AppDomain.CurrentDomain.BaseDirectory+"\\log.txt";
            using(StreamWriter sw=new StreamWriter(strPath,true))
            {
                sw.WriteLine(message);
                sw.Close();
            }
        }
    }
}

如果不使用AOP,我们就需要在记录日志的地方实例化Loghelper对象,然后记录日志:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        public void DoWork()
        {
            // 记录日志
            LgoHelper.RecoreLog("执行业务前");
            Console.WriteLine("执行订单业务");
            LgoHelper.RecoreLog("执行业务后");
        }
    }
}

我们再次运行程序,查看结果:

我们看看日志内容:

这样修改可以实现记录日志的功能。但是上面的方法会修改原先已有的代码,这就违反了开闭原则。而且添加日志也不是业务需求的变动,不应该去修改业务代码。下面使用AOP来实现。首先安装PostSharp,直接在NuGet里面搜索,然后安装即可:

然后定义一个LogAttribute类,继承自OnMethodBoundaryAspect。这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关:

using PostSharp.Aspects;
using System;

namespace PostSharpDemo
{
    [Serializable]
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class LogAttribute: OnMethodBoundaryAspect
    {
        public string ActionName { get; set; }
        public override void OnEntry(MethodExecutionArgs eventArgs)
        {
            LgoHelper.RecoreLog(ActionName + "开始执行业务前");
        }

        public override void OnExit(MethodExecutionArgs eventArgs)
        {
            LgoHelper.RecoreLog(ActionName + "业务执行完成后");
        }
    }
}

然后Log特性应用到DoWork函数上面:

using System;

namespace PostSharpDemo
{
    /// <summary>
    /// 订单业务类
    /// </summary>
    public class OrderBusiness
    {
        [Log(ActionName ="DoWork")]
        public void DoWork()
        {
            // 记录日志
            // LgoHelper.RecoreLog("执行业务前");
            Console.WriteLine("执行订单业务");
            // LgoHelper.RecoreLog("执行业务后");
        }
    }
}

这样修改以后,只需要在方法上面添加一个特性,以前记录日志的代码就可以注释掉了,这样就不会再修改业务逻辑代码了,运行程序:

在看看日志:

这样就实现了AOP功能。

我们在看看使用Remoting来实现动态代理。

首先还是创建一个User实体类:

namespace DynamicProxy.Model
{
    public class User
    {
        public string Name { get; set; }
        public string Password { get; set; }
    }
}

然后创建一个接口,里面有一个注册方法:

using DynamicProxy.Model;

namespace DynamicProxy.Services
{
    public interface IAccountService
    {
        void Reg(User user);
    }
}

然后创建接口的实现类:

using DynamicProxy.Model;
using System;

namespace DynamicProxy.Services
{
    public class AccountService : MarshalByRefObject, IAccountService
    {
        public void Reg(User user)
        {
            Console.WriteLine($"{user.Name}注册成功");
        }
    }
}

然后创建一个泛型的动态代理类:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;

namespace DynamicProxy
{
    public class DynamicProxy<T> : RealProxy
    {
        private readonly T _target;

        // 执行之前
        public Action BeforeAction { get; set; }

        // 执行之后
        public Action AfterAction { get; set; }

        // 被代理泛型类
        public DynamicProxy(T target) : base(typeof(T))
        {
            _target = target;
        }

        // 代理类调用方法
        public override IMessage Invoke(IMessage msg)
        {
            var reqMsg = msg as IMethodCallMessage;
            var target = _target as MarshalByRefObject;

            BeforeAction();
            // 这里才真正去执行代理类里面的方法
            // target表示被代理的对象,reqMsg表示要执行的方法
            var result = RemotingServices.ExecuteMessage(target, reqMsg);
            AfterAction();
            return result;
        }

    }
}

我们看到,这个泛型动态代理类里面有两个泛型委托:BeforeAction、AfterAction。通过构造函数把代理泛型类传递进去。最后调用Invoke方法执行代理类的方法。

最后我们还要创建一个代理工厂类,用来创建代理对象,通过调用动态代理来创建动态代理对象:

using System;

namespace DynamicProxy
{
    /// <summary>
    /// 动态代理工厂类
    /// </summary>
    public static class ProxyFactory
    {
        public static T Create<T>(Action before, Action after)
        {
            // 实例化被代理泛型对象
            T instance = Activator.CreateInstance<T>();
            // 实例化动态代理,创建动态代理对象
            var proxy = new DynamicProxy<T>(instance) { BeforeAction = before, AfterAction = after };
            // 返回透明代理对象
            return (T)proxy.GetTransparentProxy();
        }
    }
}

我们最后在Main方法里面调用:

using DynamicProxy.Model;
using DynamicProxy.Services;
using System;

namespace DynamicProxy
{
    class Program
    {
        static void Main(string[] args)
        {
            // 调用动态代理工厂类创建动态代理对象,传递AccountService,并且传递两个委托
            var acount = ProxyFactory.Create<AccountService>(before:() =>
            {
                Console.WriteLine("注册之前");
            }, after:() =>
            {
                Console.WriteLine("注册之后");
            });

            User user = new User()
            {
             Name="张三",
             Password="123456"
            };
            // 调用注册方法
            acount.Reg(user);

            Console.ReadKey();
        }
    }
}

程序运行结果:

这样就利用Remoting实现了动态代理。

GitHub地址:[email protected]:JiangXiaoLiang1988/AOP.git

原文地址:https://www.cnblogs.com/dotnet261010/p/12285867.html

时间: 2024-11-08 13:14:29

C#编程:AOP编程思想的相关文章

struct2.1笔记03:AOP编程和拦截器概念的简介

1.AOP编程 AOP编程,也叫面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率. AOP是OOP的延续,是(Aspect Oriented Programming)的缩写,意思是面向切面(方面)编程. 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况

Spring Boot学习——AOP编程的简单实现

首先应该明白一点,AOP是一种编程范式,是一种程序设计思想,与具体的计算机编程语言无关,所以不止是Java,像.Net等其他编程语言也有AOP的实现方式.AOP的思想理念就是将通用逻辑从业务逻辑中分离出来. 本文将通过一个HTTP请求的例子简单的讲解Spring Boot中AOP的应用,步骤如下: 第一步,添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spr

聊聊Javascript中的AOP编程

Duck punch 我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Monkey patch这个词来源于 guerrilla patch,意为在运行中悄悄的改变代码,而 guerrilla 这个词与 gorilla 同音,而后者意又与monkey相近(前者为“猩猩”的意思),最后就演变为了monkey patch. 如果你没有听说过duck punch,但你或许听说过du

聊Javascript中的AOP编程

我们先不谈AOP编程,先从duck punch编程谈起. 如果你去wikipedia中查找duck punch,你查阅到的应该是monkey patch这个词条.根据解释,Monkey patch这个词来源于 guerrilla patch,意为在运行中悄悄的改变代码,而 guerrilla这个词与 gorilla 同音,而后者意又与monkey相近(前者为“猩猩”的意思),最后就演变为了monkey patch. 如果你没有听说过duck punch,但你或许听说过duck typing.举一

Web项目中静态代理和动态代理为基础的面向切面编程AOP

本来每天更新的,我一般喜欢夜里过了十二点的时候发文章,结果难道是愚人节吗?学校的网也很有意思,断了,把我给耍了...好吧-开始今天的话题AOP.AOP太重要了,所以放到第二篇文章来谈这个话题,AOP是Spring中的重要概念.如果这个不理解Web开发中的三大框架的原理,那就呵呵了.时常听到同学和网友议论Web程序员大部分时间都是在考皮XML配置,我当时听到也是醉了,所以我要用心学习Web,其实这里面蕴含的设计模式.算法.架构思想在源码中体现的淋漓尽致啊,一个大宝库竟然视而不见可惜了.下面就一起品

AOP编程,spring实现及JDK,CGLIB实现

什么是AOP? AOP(Aspect-OrientedProgramming,面向方面编程)和OOP(Object-Oriented Programing,面向对象编程)思想不同,两者并非对立关系,前者是后者的补充,后者因为前者的补充而减少重复代码,使程序降低模块间的偶合度,增加未来代码的可操作性和可维护性. 为什么要用AOP模式? 如果我们在业务逻辑中需要对对象中的方法的调用进行记录统计等功能时,通常需要在每个类中新增一个方法来完成相应共能,如此以来代码中就会有很多重复的部分,程序也会高度偶合

Java——面向切面编程,Spring中的AOP编程

面向切面编程 AOP思想:将横向重复代码,纵向抽取出来 AOP体现--Filter AOP体现--拦截器 AOP体现--动态代理 Spring中实现AOP思想 原理:Spring可以为容器中管理的对象生成代理对象 代理分为动态代理和cglib代理: 动态代理(优先) 被代理对象必须要实现接口,才能产生代理对象,如果没有接口将不能使用动态代理技术,换句话说,就是代理对象和被代理要实现同一接口 cglib代理 第三方代理技术,cglib代理,可以对任何类生成代理,代理的原理是对目标对象进行继承代理,

前端解读面向切面编程(AOP)

前言 面向对象(OOP)作为经典的设计范式,对于我们来说可谓无人不知,还记得我们入行起始时那句经典的总结吗-万事万物皆对象. 是的,基于OOP思想封装.继承.多态的特点,我们会自然而然的遵循模块化.组件化的思维来设计开发应用,以到达易维护.可扩展.高复用的目的. 既然OOP这么多优点,那么经常被大家提起的面向切面编程(AOP)是什么回事呢,下面我们就一起来看一下. AOP定义 第一步还是要知道aop是什么,先个来自维基百科的解释: 面向侧面的程序设计(aspect-oriented progra

编程模型&amp;编程思想

编程模型 1.面向对象编程OOP 2.面向切面编程AOP Java静态接口,Java动态代理,字节码提升. 面向切面的两个方面: 拦截判断:方法,注解,参数,异常 拦截执行:前置,后置,返回,异常 3.面向元数据编程: 泛型.反射.注解 4.面向函数编程FOP 函数式接口,默认方法,方法引用 编程思想 1.契约编程:操作对象, 2.语义命名, 3.访问控制, 4.方法返回值,构造器. 5.方法参数, 6.异常错误 设计模式 1.面向对象设计模式: 构造模式,builder模式,工厂模式,抽象工厂

面向切面编程AOP——加锁、cache、logging、trace、同步等这些较通用的操作,如果都写一个类,则每个用到这些功能的类使用多继承非常难看,AOP就是解决这个问题的

面向切面编程(AOP)是一种编程思想,与OOP并不矛盾,只是它们的关注点相同.面向对象的目的在于抽象和管理,而面向切面的目的在于解耦和复用. 举两个大家都接触过的AOP的例子: 1)java中mybatis的@Transactional注解,大家知道被这个注解注释的函数立即就能获得DB的事务能力. 2)python中的with threading.Lock(),大家知道,被这个with代码块包裹的部分立即获得同步的锁机制. 这样我们把事务和加锁这两种与业务无关的逻辑抽象出来,在逻辑上解耦,并且可