第五章 面向方面編程___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.pswp.cn/news/258868.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/258868.shtml
英文地址,請注明出處:http://en.pswp.cn/news/258868.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java將xml中的標簽名稱轉為小寫_深入學習Java Web(七): JSTL標簽庫

本文轉自與博客園一杯涼茶的博客.在之前我們學過在JSP頁面上為了不使用腳本&#xff0c;所以我們有了JSP內置的行為、行為只能提供一小部分的功能&#xff0c;大多數的時候還是會用java腳本&#xff0c;接著就使用了EL表達式&#xff0c;基本上EL表達式看似能滿足我們的要求&am…

python中*args和**args的不同

上一段代碼&#xff0c;大家感受一下 def test_param(*args): print(args) def test_param2(**args): print(args) test_param(test1,test2) >>>(test1,test2) test_param2(p1test1,p2test2) >>>{p1:test1, p2:test2} python提供了兩種特別的方法來定義函數的…

halcon模板匹配學習(二) 準備模板

如下&#xff0c;我們將介紹匹配的第一個操作&#xff1a;準備模板 初始時刻&#xff0c;我們準備好參考圖像&#xff0c;并對其做一定的處理&#xff0c;然后我們需要從參考圖像中導出模板&#xff0c;也就是將參考圖像裁剪成所謂的模板圖像。獲取模板圖像可以通過設置ROI來完…

揭秘繼承技術之虛函數

虛函數 調用虛函數時函數行為將根據對象所屬類的不同而變化。 父類指針或引用指向子類對象時&#xff0c;可訪問子類重寫方法&#xff08; virtual函數&#xff09;但無法訪問在父類中沒有定義的子類方法和數據成員。 #include <iostream>using namespace std;class Supe…

java中GET方式提交和POST方式提交

java中GET方式提交的示例&#xff1a; /*** 獲取關注列表;* return*/SuppressWarnings("unchecked")public static ArrayList<String> getUserList() {StringBuffer bufferRes new StringBuffer();ArrayList<String> users null;try {URL realUrl new…

基于HALCON的模板匹配方法總結

很早就想總結一下前段時間學習HALCON的心得&#xff0c;但由于其他的事情總是抽不出時間。去年有過一段時間的集中學習&#xff0c;做了許多的練習和實驗&#xff0c;并對基于HDevelop的形狀匹配算法的參數優化進行了研究&#xff0c;寫了一篇《基于HDevelop的形狀匹配算法參數…

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.…

很有用的cv牛人的網址和主要貢獻

CV人物1&#xff1a;Jianbo Shi史建波畢業于UC Berkeley&#xff0c;導師是Jitendra Malik。其最有影響力的研究成果&#xff1a;圖像分割。其于2000年在PAMI上多人合作發表"Noramlized cuts and image segmentation"。這是圖像分割領域內最經典的算法。主頁&#xf…

c++分治法求最大最小值實現_程序員:算法導論,分治法、歸并排序,偽代碼和Java實現...

分治法我們首先先介紹分治法。分治法的思想&#xff1a;將原問題分解為幾個規模較小但類似于原問題的子問題&#xff0c;遞歸地求解這些子問題&#xff0c;然后在合并這些子問題的解來解決原問題的解。還是拿撲克牌舉例子&#xff0c;假設桌上有兩堆牌面朝上的牌(牌面朝上&…

菜根譚#82

風來疏竹&#xff0c;風過而竹不留聲&#xff1b;雁度寒潭&#xff0c;雁去而潭不留影&#xff1b;故君子事來而心始現&#xff0c;事去而心隨空。 轉載于:https://www.cnblogs.com/star4knight/p/3604403.html

解讀ASP.NET 5 MVC6系列(9):日志框架

解讀ASP.NET 5 & MVC6系列&#xff08;9&#xff09;&#xff1a;日志框架 原文:解讀ASP.NET 5 & MVC6系列&#xff08;9&#xff09;&#xff1a;日志框架框架介紹 在之前的.NET中&#xff0c;微軟還沒有提供過像樣的日志框架&#xff0c;目前能用的一些框架比如Log4N…

2017第18周四

繼續加班中&#xff0c;很多事不如預期。時間花費很多但效果不成比例。越忙落下的事越多&#xff0c;有時候還需要讓自己靜下來想想&#xff0c;到底有什么是重要的。集中精力放在重要的哪些事&#xff0c;盡自己最大努力即可&#xff0c;盡最大努力即使沒有達到也可以沒有遺憾…

halcon相關的鏈接

論壇、培訓 halcon學習網&#xff1a;http://www.ihalcon.com/鳥叔機器視覺&#xff1a;http://bbs.szvbt.com/forum.php 博客 韓兆新的博客園majunfuLife and Codingzhaojun的博客風韻無聲騎螞蟻上高速的博客小馬_xiaoLV2小新識圖程序園-程序員的世界章柯淵的博客 注&…

[轉]Java8-本地緩存

這里我將會給大家演示用ConcurrentHashMap類和lambda表達式實現一個本地緩存。因為Map有一個新的方法可以在key為Null的時候自動計算一個新的value值。非常完美的實現cache。來看下代碼&#xff1a; public static void main(String[] args) {for (int i 0; i < 10; i)Syst…

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) 函數功能&…

Java進程占用CPU資源過多分析

問題描述&#xff1a; 生產環境下的某臺tomcat7服務器&#xff0c;在剛發布時的時候一切都很正常&#xff0c;在運行一段時間后就出現CPU占用很高的問題&#xff0c;基本上是負載一天比一天高。 問題分析&#xff1a; 1&#xff0c;程序屬于CPU密集型&#xff0c;和開發溝通過&…

分針網——怎么輕松學習JavaScript

js給初學者的印象總是那么的“雜而亂”&#xff0c;相信很多初學者都在找輕松學習js的途徑。我試著總結自己學習多年js的經驗&#xff0c;希望能給后來的學習者探索出一條“輕松學習js之路”。js給人那種感覺的原因多半是因為它如下的特點&#xff1a;A&#xff1a;本身知識很抽…