上一篇讲了 AOP 和 OOP 的区别,这一次我们开始入门 AOP 。实现面向方面编程的技术,主要分为两大类:

一是 采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

二是 采用静态织入的方式,引入特定的语法创建 “方面”,从而使得编译器可以在编译期间织入有关 “方面” 的代码。

然而殊途同归,实现 AOP 的技术特性却是相同的,分别为:

crosscutting concerns (横切性关注点):一个关注点(concern)就是一个特定的目的,一块我们要完成的区域,一段我们需要的逻辑行为。从技术的角度来说,一个典型的软件系统包含一些核心的关注点和系统级的关注点。举个例子来说,一个银行支付系统的核心关注点是存入/支付处理,而系统级的关注点则是日志、事务完整性、权限、安全及性能问题等,许多关注点(即横切关注点)会在很多个模块中出现。如果使用现有的编程方法,横切关注点会横越多个模块,结果是使系统变得越来越复杂,难以设计和实现。通过面向切面编程的方式能够更好地分离系统关注点,从而提供模块化的横切关注点。

aspect(切面):横切性关注点的抽象即为切面,与类相似,只是两者的关注点不一样。类是对物体特征的抽象,切面是对横切性关注点的抽象。

join point(连接点):所谓连接点就是指那些些被拦截到的点。在Spring中这些连接点指的就是方法,因为在Spring中只支持方法类型的连接点。实际上连接点还可以是构造函数或者字段。通俗的说是程序执行中的一个精确执行点,例如类中的一个方法。它是一个抽象的概念,在实现面向切面编程时,并不需要去定义一个join point。

point cut(切入点):切入点就是指我们要对那些方法进行拦截和定义。

advice(通知):通知就是指我们拦截到方法之后,要做的事情。Spring中有前置通知,后置通知,异常通知,最终通知,环绕通知。

target object(目标对象):指包含连接点的对象。也称为被通知或被代理对象。

weave(织入):将切面应用到目标对象,并导致代理对象创建的过程叫做织入

Introduction(引入):运行期间,在不修改代码的情况下,动态的为类添加方法和字段。通俗的将就是为对象引入附加的方法或属性。

使用代理模式实现面向切面编程

  下面我们使用代理模式来模拟一下,现面向切面编程。通过上面那幅图,我们看到使用面向切面编程将核心业务和其他业务(日志记录,性能检测等)分离开来。这次我们模拟一下,银行支付中记录日志的问题。

我们有 两个接口,ICard,ILogger , ICard 表示 卡的接口,ILogger 表示 日志记录接口。

卡接口:

 1 namespace CnblogLesson_5_1.Interface
2 {
3 /// <summary>
4 /// 卡
5 /// </summary>
6 interface ICard
7 {
8 //存入
9 void Deposit(double money);
10
11 //支出
12 void Pay(double money);
13 }
14 }

日志接口:

 1 namespace CnblogLesson_5_1.Interface
2 {
3 //日志
4 interface ILogger
5 {
6 /// <summary>
7 /// 写入日志
8 /// </summary>
9 void LogWrite(string message);
10 }
11 }

卡的实现:

 1 using System;
2 using CnblogLesson_5_1.Interface;
3
4 namespace CnblogLesson_5_1.Impl
5 {
6 class Card : ICard
7 {
8 //存入
9 public void Deposit(double money)
10 {
11 Console.WriteLine("存入:{0}" ,money);
12 Logger log = new Logger();
13 log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() +"存入" + money.ToString());
14 }
15
16 //支出
17 public void Pay(double money)
18 {
19 Console.WriteLine("支出:{0}", money);
20 Logger log = new Logger();
21 log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "支出" + money.ToString());
22 }
23 }
24 }

日志的实现:

 1 using System;
2 using CnblogLesson_5_1.Interface;
3
4 namespace CnblogLesson_5_1.Impl
5 {
6 class Logger : ILogger
7 {
8 public void LogWrite(string message)
9 {
10 Console.WriteLine("写入到SQL Server 数据库中:" + message);
11 }
12 }
13 }

调用:

 1 using System;
2 using CnblogLesson_5_1.Interface;
3 using CnblogLesson_5_1.Impl;
4
5 namespace CnblogLesson_5_1
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 ICard card = new Card();
12
13 card.Deposit(100);
14 card.Pay(100);
15
16 Console.ReadKey();
17
18 }
19 }
20 }

输出结果:

 
以上方式的缺陷:
  我们的核心业务(存入/取钱)与记录日志本不该彼此纠缠在一起的责任却纠缠在一起,增加了我们系统的复杂性。
 
下面使用代理模式模拟 AOP 实现 核心业务与日志记录的解耦:
 
ICard 和 ILogger 接口,还是那些接口,日志的实现还是日志的实现,没有做改动。
现在,存款和取款的 实现只做自己的业务,无需进行日志记录:
 1 using System;
2 using 代理模式模拟AOP.Interface;
3
4 namespace 代理模式模拟AOP.Impl
5 {
6 class Card : ICard
7 {
8 //存入
9 public void Deposit(double money)
10 {
11 Console.WriteLine("存入:{0}" ,money);
12 }
13
14 //支出
15 public void Pay(double money)
16 {
17 Console.WriteLine("支出:{0}", money);
18 }
19 }
20 }

现在增加代理类 ProxyCard:

 1 using System;
2 using 代理模式模拟AOP.Interface;
3 using 代理模式模拟AOP.Impl;
4
5 namespace 代理模式模拟AOP.Proxy
6 {
7 public class ProxyCard
8 {
9 private ICard target;
10
11 public ProxyCard(ICard target)
12 {
13 this.target = target;
14 }
15
16 public void Invoke(string method, object[] parameters)
17 {
18 if (target != null)
19 {
20 ILogger log = new Logger();
21 double money = double.Parse(parameters[0].ToString());
22 switch (method) {
23 case "Pay":
24 log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "支出" + money.ToString());
25 break;
26 case "Deposit":
27 log.LogWrite("日志:" + DateTime.Now.ToShortTimeString() + "存入" + money.ToString());
28 break;
29 }
30 Type type = target.GetType();
31 type.GetMethod(method).Invoke(target, parameters);
32 }
33 }
34 }
35
36 }

调用:

 1 using System;
2 using 代理模式模拟AOP.Interface;
3 using 代理模式模拟AOP.Impl;
4 using 代理模式模拟AOP.Proxy;
5
6 namespace 代理模式模拟AOP
7 {
8 class Program
9 {
10 static void Main(string[] args)
11 {
12 ICard card = new Card();
13
14 ProxyCard proxy = new ProxyCard(card);
15 proxy.Invoke("Pay", new object[] { 100 });
16 proxy.Invoke("Deposit", new object[] { 100 });
17
18 Console.ReadKey();
19
20 }
21 }
22 }

执行结果:

 
通过 ProxyCard 代理对象,我们实现了对方法的拦截,在调用之前进行日志记录的操作。实现了我们的核心业务(存入/支出)与日志记录的分离,从而降低了系统的耦合。

第五章 面向方面编程___AOP入门的更多相关文章

  1. 第五章 面向方面编程___OOP和AOP随想

    面向方面编程,又称面向切面编程(Aspect-Oriented-Programming),英文缩写 AOP,可以说是 OOP(Object-Oriented-Programming)面向对象编程的补充 ...

  2. Spring详解(五)------面向切面编程

    .AOP 什么? AOP(Aspect Oriented Programming),通常称为面向切面编程.它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的 ...

  3. Spring企业级程序设计 • 【第3章 面向切面编程】

    全部章节   >>>> 本章目录 3.1 AOP基本概念和术语 3.1.1 AOP概念 3.1.2 AOP的术语解释 3.1.3 通知类型介绍 3.1.4 通过AOP模拟事务操 ...

  4. Spring之AOP(面向切面编程)_入门Demo

    AOP是OOP的延续,是Aspect Oriented Programming的缩写,意思是面向切面编程.AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,AOP可 ...

  5. opencv图像处理基础 (《OpenCV编程入门--毛星云》学习笔记一---五章)

    #include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgu ...

  6. C#面向服务编程技术WCF从入门到实战演练

    一.WCF课程介绍 1.1.Web Service会被WCF取代吗? 对于这个问题阿笨的回答是:两者在功能特性上却是有新旧之分,但是对于特定的系统,适合自己的就是最好的.不能哪一个技术框架和行业标准作 ...

  7. 【React】学习笔记(一)——React入门、面向组件编程、函数柯里化

    课程原视频:https://www.bilibili.com/video/BV1wy4y1D7JT?p=2&spm_id_from=pageDriver 目录 一.React 概述 1.1.R ...

  8. 《java编程思想》读书笔记(一)开篇&第五章(1)

    2017 ---新篇章  今天终于找到阅读<java编程思想>这本书方法了,表示打开了一个新世界. 第一章:对象导论 内容不多但也有20页,主要是对整本书的一个概括.因为已经有过完整JAV ...

  9. UNIX 网络编程第五章读书笔记

    刚看完 UNIX 第五章内容,我想按照自己的方式将自己获得的知识梳理一遍,以便日后查看!先贴上一段简单的 TCP 服务器端代码: #include <sys/socket.h> #incl ...

随机推荐

  1. py自动化之环境配置

    1,官网下载py,点击安装,配置环境变量 2,下载setuptools,用于安装pip (python setup.py install) 3,下载pip,用于安装selenium(pip insta ...

  2. Echarts的option中的data问题

    option = { title : { text: '某站点用户访问来源', subtext: '纯属虚构', x:'center' }, tooltip : { trigger: 'item', ...

  3. IDEA用maven打war包

    打包其实很简单: 把tomcat停掉,点击Maven Projects ,点击clean , 点击package 自动打包完成. 查看包位置: 这是包的位置,通过查看PATH就可以知道你的包在哪里了. ...

  4. centos6.4或者6.5使用yum的elrepo源升级内核

    本文转自:http://www.511yj.com/centos-yum-kernel.html 今天想在centos6.5安装docker,在网上查了说centos6.5需要64位的,内核需要升级到 ...

  5. zookeeper原生API做java客户端

    简介 本文是使用apache提供的原生api做zookeeper客户端 jar包 zookeeper-3.4.5.jar   Demo package bjsxt.zookeeper.base; im ...

  6. 【WPF】给UserControl引入多个资源

    问题:为了方便资源的复用,我们通常会把资源单独抽取为一个资源文件,供其他文件引用.而用户自定义控件UserControl中经常需要引入多个资源文件.而在XAML中由于标签UserControl.Res ...

  7. C语言 · 阿尔法乘积

    算法训练 阿尔法乘积   时间限制:1.0s   内存限制:512.0MB        问题描述 计算一个整数的阿尔法乘积.对于一个整数x来说,它的阿尔法乘积是这样来计算的:如果x是一个个位数,那么 ...

  8. 多个git账号之间的切换

    在这篇文章中: 介绍 处理 一些题外话 我有一个repo,想要同时push到不同的仓库该如何设置? 我有一个github的repo,clone没有问题,push的时候总是报错:error: The r ...

  9. 上手并过渡到PHP7(1)——基于Homestead的PHP7和XDdebug环境

    PHP7 up and running 泊学实操视频泊学原文链接PHP7, Xdebug and Homestead 在经历了13个RC版本之后,PHP 7终于来了.在我们上手评估PHP 7的新特性之 ...

  10. 16 款最流行的JavaScript 框架

    1. jQuery – Javascript框架 jQuery 是最流行的 JavaScript 框架,它简化了HTML 文档遍历.事件处理.动画和Ajax交互.jQuery插件非常之多. 2. Do ...