上一篇讲了 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.Interface2 {3     /// <summary>4     /// 卡5     /// </summary>6     interface ICard7     {8         //存入9         void Deposit(double money);
10
11         //支出
12         void Pay(double money);
13     }
14 }

日志接口:

 1 namespace CnblogLesson_5_1.Interface2 {3     //日志4     interface ILogger5     {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.Impl5 {6     class Card : ICard7     {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.Impl5 {6     class Logger : ILogger7     {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_16 {7     class Program8     {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.Impl5 {6     class Card : ICard7     {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.Proxy6 {7     public class ProxyCard8     {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 代理模式模拟AOP7 {8     class Program9     {
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. 《Kotlin 程序设计》第五章 Kotlin 面向对象编程(OOP)

    第五章 Kotlin 面向对象编程(OOP) 正式上架:<Kotlin极简教程>Official on shelves: Kotlin Programming minimalist tut ...

  2. 第五章-分布式并行编程框架MapReduce

    第五章-分布式并行编程框架MapReduce 文章目录 第五章-分布式并行编程框架MapReduce MapReduce概述 分布式并行编程 MapReduce模型和函数 MapReduce体系结构 ...

  3. 第6章 面向方面编程

    第6章 面向方面编程 6.1 AOP概念 AOP是Aspect Oriented Programming的简写,中文通常译作面向方面编程,其核心内容就是所谓的"横切关注点".[17 ...

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

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

  5. Spring--官方文档部分翻译(第五章 面向Aspect的编程-AOP)

    AOP通过提供程序设计的另一种思路扩展了OOP,OOP的核心元素是class,而AOP的核心是Aspect. Aspect使得关注点模块化. AOP是spring的核心模块.虽然LOC容器不依赖AOP ...

  6. python嵩天第二版第五章_如何避免从入门到放弃——python小组学习复盘

    2019年春节python学习行动复盘2019-02-09 为了主攻python,没有参加心理学晨读.对心理学也不敢兴趣,怕耽误学习python的时间. 那么没学习心理学的情况下,python学的怎么 ...

  7. Kotlin第五章: android网络编程

    1. Android网络编程 OkHttp OkHttp是一个高效的HTTP客户端,它的横空出世,让其他的网络请求框架都变得黯然失色. Retrofit Retrofit是一个基于OkHttp的RES ...

  8. 算法竞赛入门经典(第2版)—第五章(C++与STL入门)

    文章目录 零碎知识点整理 题目 10474 - Where is the Marble? 101 - The Blocks Problem 10815 - Andy's First Dictionar ...

  9. python编程从入门到实践第九章——类

    相关文章链接: python编程从入门到实践第二章--变量和简单数据类型 python编程从入门到实践第三章--列表简介 python编程从入门到实践第四章--操作列表 python编程从入门到实践第 ...

最新文章

  1. lodop打印无内容_民法典新确立的打印遗嘱应如何订立能有效?| 附文书范本
  2. Tungsten Fabric SDN — 与 Bare Metal 的集成架构
  3. Servlet——简单用户登录实例+http协议解析
  4. 【HDU 1501】Zipper(记忆化搜索)
  5. LeetCode 78 子集 中等难度
  6. Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制--转载
  7. Android深度探索(卷1)HAL与驱动开发第六章总结
  8. 你真的了解扩展方法吗?
  9. qiaoye.php,全自动无限生成关键词页面(黑帽SEO优化终极方法)
  10. java将异常输出到日志_【ThinkingInJava】25、将异常输出记录到日志
  11. python创建实例属性_Python学习笔记__6.5章 实例属性和类属性
  12. django+uwsgi+nginx部署
  13. python 生成随机数: 随机整数,随机小数,0-1之间的小数
  14. 正交表测试与混合正交表工具
  15. Excel数据分析高级技巧②——数据透视表(组合/切片器/计算字段/数据透视图/条件格式)
  16. win10彻底禁用chrome自动升级方法
  17. 单片机课设中期报告_毕业论文--中期检查情况报告(40页)详解.doc
  18. 3. 用户/管理员注册登录 - 如何使用个人Facebook来登录门户网站
  19. 【es6】用map对数组对象中插入新的属性
  20. C盘莫名其妙的增加50+G,解决方案

热门文章

  1. php页面空白如何解决,php页面空白怎么回事 php出现空白页的解决方法
  2. redis连不上java,java使用jedis连不上linux上redis服务
  3. LeetCode 97: 交错字符串
  4. hadoop学习3 查找块的位置
  5. Tensorflow 指令加速
  6. 比较python类的两个instance(对象) 是否相等
  7. python 之configparser模块
  8. 前端性能优化 Web前端应该从哪些方面来优化网站?
  9. [转]第一章 Windows Shell是什么 【来源:http://blog.csdn.net/wangqiulin123456/article/details/7987862】...
  10. 对IEnumerableT,IDictionaryTkey,TValue,ICollectionT,IListT的总结