面向切面編程(Aspect-Oriented Programming)最重要的一個概念就是“關注點的分離(separation of concerns)”。
對於這個概念,我一向不能體會。今天回憶Python,Ruby編程知識時突然來了感覺。做個記號。
1,從重複的代碼說起。
時常寫代碼,時常寫重複的代碼,時常寫那些看似無用的重複代碼,時常寫那些看似無用又不得不寫的代碼。
在應用系統編程中,我們時常在Login相關的方法中添加對許可權檢查的代碼,形如:
1public void OnLogin()
2{
3 if (Session["Privilege"] != "Admin")
4 {
5 throw ApplicationException("Unauthenticated");
6 return;
7 }
8 //Other Codes
9}
類似這樣的代碼在每個頁面都會出現。
我們從代碼結構上看到OnLogin方法基本上由以下兩個方面(切面)組成
//A,執行許可權檢查——重複
//B,執行其它事務
對於"A,執行許可權檢查"來說該部分代碼在每個頁面中都是一樣的,且相對不會發生改變的——只要執行正常的許可權檢查都需要該部分代碼。
怎麼辦?
最常用的一個方法是"封裝方法",將執行許可權檢查那部分代碼封裝成靜態方法調用,形如:
1public void OnLogin()
2{
3 Common.CheckPrivilege("Admin");
4 //Other Codes
5}
這樣已經開始將關注點封裝起來了,但還是還差一點:我們還要將其分離——在不同的方法中,在不同的檔案中。
其實對用戶端代碼來說,我們最理想的方法莫過於:
1[PrivilegeCheck("Admin")]
2public void OnLogin()
3{
4 //Other Codes
5}
通過自訂屬性(Custom Attibutes)我們將“執行許可權檢查”的代碼和“執行其它任務“的代碼完全分開的,不僅邏輯上分開,物理上也分開了(兩個檔案)。更重要的是我們可以動態地構建一個通過(模版)代碼,在運行時(Runtime)將兩個切面的代碼進行粘合。從而得到最大的靈活性和客戶代碼的簡單性。
2,什麼是切面/關注點。
曾看過一篇文章說AOP是OOP的升級,當時不懂AOP,也不知道是說啥,現在好像明白了一些。
我們想要將關注點分離,首先得找到關注點。例如上例中的“許可權檢查”部分。在“許可權檢查”和“其它任務”之間,我們構建一個切面,將以上兩個關注點分開。
以我目前瞭解,理解鎖裝並成功實現封裝是實現AOP的第一步。 其次是尋找一個合適的切面。
3,一個AOP小樣本。
為了加深理解,我使用AOP的觀念寫了範例程式碼,用來執行登陸時的許可權檢查。
AOP小樣本
4,有了AOP我們能做些什麼?
我們時常可以在各類架構中看到AOP的運用。其實需要“將注點分離”的地方都可以使用AOP。比如執行Logging,執行資料庫的Transaction,都要需要大量重複且不得不寫的代碼,這些地方也是AOP常被應用的地方。
但任何東西都有利弊,AOP無疑還是加大了Debug,理解和實現的難度,增加了複雜性。我們在使用AOP之前還是需要考量一下是否確實需要AOP。我們不必急著AOP,當需要的時候,我們可以重構到AOP。