摘要:面向對象的思想強調"一切皆是對象",在面向對象的程序中我們使用真實概念的模型思考問題,使得整個軟件系統開發可以像搭建房屋一樣有條不紊。然而面向對象也並非完美無缺的,它更注重於對象層次結構方面的東西,對於如何更好的管理對象行爲內部結構,還存在着些許不足。那麼我們如何使這個問題的得到更完美的解決呢?答案就是AOP。
主要內容:
- AOP簡述
- 利用動態代理實現AOP
- 總結
一、AOP簡述
AOP的概念早在上個世紀九十年代初就已經出現了,當時的研究人員通過對面向對象思想侷限性的分析研究出了一種新的編程思想來幫助開發者減少代碼重複提高開發效率,那就是AOP,Aspect-Oriented Programming。AOP是OOP的補充,是GOF的延續。我們知道設計模式是對於面向對象設計中經驗的總結,它孜孜不斷追求的就是調用者與被調用者之間的解耦。有了設計模式我們可以更有效的利用面向對象的特性,使得整個軟件設計更加靈活、優雅。但是設計模式是基於面向對象的思想而形成的,更多的時候關注的是對象層次的東西,在解決對象行爲內部問題方面卻有些不足。AOP的出現恰恰就是對面向對象思想做出了完美的補充。
上圖顯示了軟件的縱向和橫向結構,從縱向結構來看就是我們軟件系統的各個模塊,它主要負責處理我們的核心業務(例如商品訂購、購物車查看);而從橫向結構來看,我們幾乎每個系統又包含一些公共模塊(例如權限、日誌模塊等)。這些公共模塊分佈於我們各個核心業務之中(例如訂購和查看商品明細的過程都需要檢查用戶權限、記錄系統日誌等)。這樣一來不僅在開發過程中要處處關注公共模塊的處理而且開發後維護起來也是十分麻煩。而有了AOP之後將應用程序中的商業邏輯同對其提供支持的通用服務進行分離,使得開發人員可以更多的關注核心業務開發。
二、利用動態實現AOP
上面我們說了一些關於AOP所要解決的問題以及這樣做的好處,下面我們主要看一下如何實現AOP。
AOP的實現一般分爲:動態代理(DynamicProxy)和靜態織入(StaticWeave)兩種方式。這裏我們主要說的是如何利用Emit來自己實現動態代理方式的AOP(關於Emit的知識大家可以看一下我的另一篇博客反射發出--Emit),以此來幫助大家更深入的理解AOP。
在開始動態代理之前假設我們有這樣一個類,它是負責處理我們的業務邏輯的。
先看對應接口
相應的類
現在我們需要給所有的核心業務添加日誌記錄功能,此時大概會有下面幾種選擇:
1.在ShowMessage和Calculate內部都添加上記錄日誌的代碼 。
2.重新寫一個類繼承於MyBusinessLogic並對其中的方法重寫。
3.寫一個靜態代理類。
首先看一下代理中用到的攔截器接口
然後編寫一個操作日誌的攔截器
再看靜態代理類
接着我們可以使用下面的代碼做測試
4.使用動態代理
相對於前兩種方法,第三種方法應該算是比較好的方法了,可是做起來比較麻煩。不僅必須給每個業務類都重新寫一個包含日誌處理的代理類,而且如果我有其他類似日誌處理的模塊(例如權限模塊)需要添加還要再寫包含其他功能的代理類。這樣做起來不僅工作量大,而且再維護起來也十分麻煩。怎麼辦?方法就是使用動態代理。
我們下面要實現的動態代理,其運行機制和上面說的靜態代理可以說是完全相同的(事實上我們編寫Emit的時候就是仿照靜態代理類來寫的),只不過重複寫代理類的工作交給程序來做了而已。
具體過程:首先根據泛型類型創建名字爲"泛型+Proxy"的類;在類中聲明一個IInterceptor型的私有變量_interceptor賦值爲null;接着創建構造函數,其參數爲IInterceptor類型;然後我們遍歷泛型中的方法,創建名稱、返回類型、參數均與泛型方法一致的方法,然後在方法中使用interceptor的Invoke方法調用對應的方法(參數分別爲泛型對象、方法名和參數);最後實例化此類,並將其返回。
最後我們測試一下
運行效果
三、總結:
上面簡單的介紹瞭如何用動態代理的方式實現AOP,主要是幫助大家理解動態代理AOP的大致思路。在實際開發中我們可能更多時候會選擇一些AOP的工具(例如Castle中的Aspect#、Spring AOP、AspectDNG等),這些內容(包括靜態織入方式實現AOP)我們今後有機會再一塊學習。