面向方面編程簡介
目錄
1. 面向切面編程的定義
2. 用Javascript應(yīng)用AOP
3. AOP核心概念詳解
4. 關(guān)于 AOP 的幾點(diǎn)思考
面向方面的編程定義
在計算中,面向方面編程(AOP)是一種編程范式,旨在通過允許分離橫切關(guān)注點(diǎn)來增加模塊化。
交叉問題是影響其他問題的程序的各個方面。在設(shè)計和實(shí)現(xiàn)中,這些問題通常無法從系統(tǒng)的其余部分清楚地分解出來,并且可能導(dǎo)致分散(代碼重復(fù))、混亂(系統(tǒng)之間的顯著依賴性)。
往往是交叉問題的例子包括:
緩存
數(shù)據(jù)驗(yàn)證
記錄
格式化數(shù)據(jù)
事務(wù)處理
……
以這個場景為例:
您開發(fā)了一個具有大量getter 方法的服務(wù),以從數(shù)據(jù)庫中獲取數(shù)據(jù)并將結(jié)果格式化為 JSON 字符串。
服務(wù)類{ getUser ({id, name}) {
如果 (!Number.isInteger(id))
返回空
const user = DAO.fetch(User, id, name) 返回 JSON.stringify(user)
}
獲取文章({id}){
如果 (!Number.isInteger(id))
返回空
const article = DAO.fetch(文章, id)
返回 JSON.stringify(文章)
}
// 獲取 Xyz ...}
數(shù)據(jù)訪問對象(DAO) 可以簡化為:
const DAO = {
// 數(shù)據(jù)庫訪問,在這里查詢和檢索結(jié)果
獲?。P?,...參數(shù)){
返回新模型(...參數(shù))
}}
這是您的模型:
類文章{
構(gòu)造函數(shù)(id){
這個.id = id
}}類用戶{
構(gòu)造函數(shù)(id,名稱){
這個.id = id
this.name = 名稱
}}
如您所見,Service的任何getter 方法都可以分為 3 個部分(或 3 個關(guān)注點(diǎn)):
數(shù)據(jù)驗(yàn)證:檢查id 是否為整數(shù)。
主要關(guān)注:與數(shù)據(jù)訪問層通信。
格式化數(shù)據(jù):將結(jié)果轉(zhuǎn)換為 JSON 字符串。
在這個例子中,這 3 個問題被過度簡化了。但在實(shí)際應(yīng)用程序中,主要關(guān)注點(diǎn)、數(shù)據(jù)驗(yàn)證和格式數(shù)據(jù)邏輯可能會變得非常復(fù)雜。
數(shù)據(jù)驗(yàn)證和格式數(shù)據(jù)邏輯是橫切關(guān)注點(diǎn),應(yīng)該與主要關(guān)注點(diǎn)隔離開來,因?yàn)樗鼈儠稚㈤_發(fā)人員對主要業(yè)務(wù)邏輯的注意力。
因此,我們應(yīng)該將它們分開并放在三個不同的地方:
服務(wù)模塊應(yīng)該只處理主要關(guān)注點(diǎn),或者核心業(yè)務(wù)邏輯。
數(shù)據(jù)驗(yàn)證模塊應(yīng)該只負(fù)責(zé)驗(yàn)證數(shù)據(jù)。
格式化數(shù)據(jù)模塊應(yīng)該只負(fù)責(zé)格式化數(shù)據(jù)。
使用 Javascript 應(yīng)用 AOP
有許多庫和框架允許我們實(shí)現(xiàn) AOP 解決方案來應(yīng)對橫切關(guān)注點(diǎn)。
在這里,我們使用 Javascript 庫:方面.js
從主要關(guān)注點(diǎn)中刪除所有橫切關(guān)注點(diǎn),我們重寫服務(wù) 模塊如下:
從 'aspect.js' @Advised ()導(dǎo)入 { Advised }類服務(wù){(diào)
getUser({id, name}) {
返回 DAO.fetch(用戶,ID,名稱)
}
getArticle({id}) {
返回 DAO.fetch(文章,id)
}}
@Advised裝飾器 有助于將ValidateAspect 和FormatAspect 連接到服務(wù) 類中。Service的實(shí)現(xiàn) 非常簡潔易讀。它只專注于它的主要職責(zé)。
最后,我們可以嘗試調(diào)用一些方法來查看結(jié)果:
const service = new Service()控制臺。日志(service.getArticle({id: '1'}))// 空控制臺。日志(service.getUser({id: 2, name: 'Hello Kitty'}))// {"id":2,"name":"Hello Kitty"}
AOP 的核心概念解釋
1/ 看點(diǎn)
方面是具有一組橫切功能的模塊。
例如:ValidateAspect,FormatAspect
為了形成切面,我們定義了切入點(diǎn)和建議。
2/ 加入點(diǎn)
連接點(diǎn)是應(yīng)用程序中我們可以插入 AOP切面的特定點(diǎn)。比如方法執(zhí)行、異常處理、變量修改……很多時候,一個連接點(diǎn)代表一個方法執(zhí)行。
3/ 建議
建議是在特定連接點(diǎn)采取的行動。換句話說,它是在連接點(diǎn)之前或之后執(zhí)行的實(shí)際代碼。
例如:@beforeMethod、@afterMethod、 @aroundMethod
4/ 切入點(diǎn)
切入點(diǎn)是與連接點(diǎn)匹配以確定是否需要運(yùn)行建議的謂詞。根據(jù)庫或框架,可以使用模式或表達(dá)式以不同方式指定切入點(diǎn)。
與圖書館方面.js本文中使用的切入點(diǎn)是用 Javascript 正則表達(dá)式 (Regex) 指定的:
{
類名模式:/.*/,
方法名稱模式:/^(get)/ }
5/ 目標(biāo)對象
目標(biāo)對象是由一個或多個方面建議的對象。也稱為建議對象。
例如:示例中使用的服務(wù)類。
6/ 編織
編織是將方面與其他對象鏈接起來以創(chuàng)建建議對象的過程。
例如:使用@Advised裝飾器在服務(wù)類上應(yīng)用編織。
關(guān)于 AOP 的幾點(diǎn)思考
好處
擁抱模塊化。
減少依賴之間的耦合。
使代碼更易于閱讀、重用和維護(hù)。
缺點(diǎn)
不包含在編程語言中,必須依賴庫才能工作。
調(diào)試可能很困難,因?yàn)榇a流遠(yuǎn)不止于此。
要求紀(jì)律不要過度使用。
面向方面編程在 OOP 世界中被認(rèn)為是“黑暗藝術(shù)”,因?yàn)樗梢愿深A(yù)您的代碼并在幕后執(zhí)行一些黑魔法。例如,它可以修改您的方法、替換結(jié)果,甚至阻止您的代碼執(zhí)行。
盡管它提供了所有的功能,但我們應(yīng)該小心并深刻理解地使用 AOP。在您的應(yīng)用程序中不必要地使用 AOP 可能是有害的,并可能導(dǎo)致許多意外錯誤。
面向方面編程并不是面向?qū)ο缶幊痰?/span>絕對替代。相反,他們是同伴。
面向方面編程通過提供另一種思考程序結(jié)構(gòu)的方式來補(bǔ)充面向?qū)ο缶幊獭?/span>OOP 中模塊化的關(guān)鍵單元是類,而在 AOP 中模塊化的單元是方面。