第五章 面向方面编程___AOP入门

上一篇讲了 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 代理对象,我们实现了对方法的拦截,在调用之前进行日志记录的操作。实现了我们的核心业务(存入/支出)与日志记录的分离,从而降低了系统的耦合。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/258868.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java将xml中的标签名称转为小写_深入学习Java Web(七): JSTL标签库

本文转自与博客园一杯凉茶的博客.在之前我们学过在JSP页面上为了不使用脚本&#xff0c;所以我们有了JSP内置的行为、行为只能提供一小部分的功能&#xff0c;大多数的时候还是会用java脚本&#xff0c;接着就使用了EL表达式&#xff0c;基本上EL表达式看似能满足我们的要求&am…

halcon模板匹配学习(二) 准备模板

如下&#xff0c;我们将介绍匹配的第一个操作&#xff1a;准备模板 初始时刻&#xff0c;我们准备好参考图像&#xff0c;并对其做一定的处理&#xff0c;然后我们需要从参考图像中导出模板&#xff0c;也就是将参考图像裁剪成所谓的模板图像。获取模板图像可以通过设置ROI来完…

揭秘继承技术之虚函数

虚函数 调用虚函数时函数行为将根据对象所属类的不同而变化。 父类指针或引用指向子类对象时&#xff0c;可访问子类重写方法&#xff08; virtual函数&#xff09;但无法访问在父类中没有定义的子类方法和数据成员。 #include <iostream>using namespace std;class Supe…

js 数组移除_2020前端面试--常见的js面试题

&#xff08;答案持续更新...&#xff09; 1.简述同步和异步的区别js是一门单线程语言&#xff0c;所谓"单线程"&#xff0c;就是指一次只能完成一件任务。如果有多个任务&#xff0c;就必须排队&#xff0c;前面一个任务完成&#xff0c;再执行后面一个任务&#xf…

spring-自动加载配置文件\使用属性文件注入

在上一篇jsf环境搭建的基础上 , 加入spring框架 , 先看下目录结构 src/main/resources 这个source folder 放置web项目所需的主要配置,打包时,会自动打包到WEB-INF下 首先看下pom.xml,需要引入一些依赖项: 1 <project xmlns"http://maven.apache.org/POM/4.0.0" x…

pygame碰撞检测

最近在学Pygame,花一段时间做了一个异常简陋版的"打砖块". 这次重点说一下困扰我比较长时间的碰撞检测(个人太菜..). 按照网上教程比较普遍的方法(也可能是我没看见别的),碰撞检测依次计算移动物体与被碰撞物体各个边之间坐标是否相交.例如下列代码,检测小球与窗口的…

2017-5-4 进程

进程&#xff1a;一个应用程序就是一个进程开启某个进程Process.Start("文件缩写名");通过绝对路径开启某个进程Process p new Process();p.StartInfo new ProcessStartInfo("要打开的程序绝对路径");p.Start(); 获取全部开启的进程&#xff1a;Process.…

c++分治法求最大最小值实现_程序员:算法导论,分治法、归并排序,伪代码和Java实现...

分治法我们首先先介绍分治法。分治法的思想&#xff1a;将原问题分解为几个规模较小但类似于原问题的子问题&#xff0c;递归地求解这些子问题&#xff0c;然后在合并这些子问题的解来解决原问题的解。还是拿扑克牌举例子&#xff0c;假设桌上有两堆牌面朝上的牌(牌面朝上&…

halcon相关的链接

论坛、培训 halcon学习网&#xff1a;http://www.ihalcon.com/鸟叔机器视觉&#xff1a;http://bbs.szvbt.com/forum.php 博客 韩兆新的博客园majunfuLife and Codingzhaojun的博客風韻無聲骑蚂蚁上高速的博客小马_xiaoLV2小新识图程序园-程序员的世界章柯渊的博客 注&…

python opencv图像处理程序_Python-OpenCV学习(四):基本图像处理

转载请注明出处&#xff1a;danscarlett的博客园 参考资料&#xff1a; 目录&#xff1a; 读取 imread 显示 imshow 存储 imwrite 缩放 resize 加边框 copyMakeBorder 裁剪 img[x_start:x_end,y_start:y_end] 1.图像读取&#xff1a; cv2.imread(fileName,flagsNone) 函数功能&…

分针网——怎么轻松学习JavaScript

js给初学者的印象总是那么的“杂而乱”&#xff0c;相信很多初学者都在找轻松学习js的途径。我试着总结自己学习多年js的经验&#xff0c;希望能给后来的学习者探索出一条“轻松学习js之路”。js给人那种感觉的原因多半是因为它如下的特点&#xff1a;A&#xff1a;本身知识很抽…

python时间序列分析航空旅人_用python做时间序列预测一:初识概念

利用时间序列预测方法&#xff0c;我们可以基于历史的情况来预测未来的情况。比如共享单车每日租车数&#xff0c;食堂每日就餐人数等等&#xff0c;都是基于各自历史的情况来预测的。 什么是时间序列&#xff1f; 时间序列&#xff0c;是指同一个变量在连续且固定的时间间隔上…

[Logstash-input-redis] 使用详解

2019独角兽企业重金招聘Python工程师标准>>> Redis插件参数配置详解 工作流程 logstash启动redis插件redis插件获取参数&#xff0c;进行校验工作判断监听模式(list,channel,pattern_channel等)&#xff0c;根据不同的监听模式创建监听任务创建redis实例&#xff0c…

雅可比旋转求解对称二维矩阵的特征值和特征向量

问题描述&#xff1a; 给定一个矩阵&#xff0c;如下&#xff1a; A[a11a21a12a22]A=\begin{bmatrix} a_{11}&a_{12}\\ a_{21}& a_{22} \end{bmatrix} 其中满足a12a21.也就是所谓的 对称矩阵。那么如何求解此矩阵的特征值以及特征向量呢&#xff1f;这里我们要用到 …

python画图数据的平均值怎么算的_Python气象数据处理与绘图(2):常用数据计算方法...

对于气象绘图来讲&#xff0c;第一步是对数据的处理&#xff0c;通过各类公式&#xff0c;或者统计方法将原始数据处理为目标数据。 按照气象统计课程的内容&#xff0c;我给出了一些常用到的统计方法的对应函数&#xff1a; import numpy as np 平均值 在计算气候态&#xff0…

Linux下nginx安装与配置

部分Linux发布版的默认安装已经集成了nginx&#xff0c;查看方法ls /usr/local&#xff0c;若已有nginx文件夹说明已集成。nginx依赖库pcre与zlib&#xff0c;且pcre依赖于gcc与gcc-c&#xff0c;因此安装步骤为&#xff1a;安装gcc与gcc-c库安装pcre库安装zlib库安装nginx详细…

几种字符串加密解密的方法

为什么80%的码农都做不了架构师&#xff1f;>>> 第一种&#xff1a;〔 Python 与 Bash Shell 的结合 〕 这个命令会让你输入一个字符串&#xff0c;然后会再输出一串加密了的数字。 加密代码[照直输入]: python -c print reduce(lambda a,b: a*256ord(b), raw_inpu…

java delegate怎么写_美团面试官:你说你们公司的Mybatis分页插件是你写的,给我说说它的设计原理?...

来源&#xff1a;http://my.oschina.net/zudajun大多数框架&#xff0c;都支持插件&#xff0c;用户可通过编写插件来自行扩展功能&#xff0c;Mybatis也不例外。我们从插件配置、插件编写、插件运行原理、插件注册与执行拦截的时机、初始化插件、分页插件的原理等六个方面展开…

SharePoint 2013 处理videoplayerpage.aspx下的个人图片显示有误问题

问题&#xff1a;Personal sites photo cant correct display in the videos pageThe url address of personal sites photo is exist surplus characters. The correct situation is just the characters of "%20", not the characters of "%2520".解决方…

clover引导mbr安装黑苹果_安装黑苹果记录(一)

从来没有接触过macOS(苹果系统)&#xff0c;孩子说他用的那台电脑linux不能安装一些软件&#xff0c;问我能不能安装黑苹果&#xff0c;一些软件只有win和mac的客户端&#xff0c;却没有linux版本。他知道我不会给他安装Windows&#xff0c;一个是怕他玩游戏&#xff0c;另外一…