JavaScript中的AOP編程的基本實現(xiàn)_第1頁
JavaScript中的AOP編程的基本實現(xiàn)_第2頁
JavaScript中的AOP編程的基本實現(xiàn)_第3頁
JavaScript中的AOP編程的基本實現(xiàn)_第4頁
JavaScript中的AOP編程的基本實現(xiàn)_第5頁
已閱讀5頁,還剩1頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第JavaScript中的AOP編程的基本實現(xiàn)AOP簡介

AOP(面向切面編程)的主要作用是把一些跟核心業(yè)務(wù)邏輯模塊無關(guān)的功能抽離出來,這些跟業(yè)務(wù)邏輯無關(guān)的功能通常包括日志統(tǒng)計、安全控制、異常處理等。把這些功能抽離出來之后,再通過“動態(tài)織入”的方式摻入業(yè)務(wù)邏輯模塊中。

面向切面編程給我們提供了一個方法,讓我們可以在不修改目標邏輯的情況下,將代碼注入到現(xiàn)有的函數(shù)或?qū)ο笾小?/p>

雖然不是必須的,但注入的代碼意味著具有橫切關(guān)注點,比如添加日志功能、調(diào)試元數(shù)據(jù)或其它不太通用的但可以注入額外的行為,而不影響原始代碼的內(nèi)容。

給你舉一個合適的例子,假設(shè)你已經(jīng)寫好了業(yè)務(wù)邏輯,但是現(xiàn)在你意識到?jīng)]有添加日志代碼。通常的方法是將日志邏輯集中到一個新的模塊中,然后逐個函數(shù)添加日志信息。

然而,如果你可以獲取同一個日志程序,在你想要記錄的每個方法執(zhí)行過程中的特定節(jié)點,只需一行代碼就可將程序注入,那么這肯定會給你帶來很多便利。難道不是嗎?

切面、通知和切點(是什么、在何時、在何地)

為了使上面的定義更形式化一點,讓我們以日志程序為例,介紹有關(guān)AOP的三個概念。如果你決定進一步研究這個范式,這些將對你有所幫助:

切面(是什么):這是你想要注入到你的目標代碼的“切面”或者行為。在我們的上下文環(huán)境(JavaScript)中,這指的是封裝了你想要添加的行為的函數(shù)。

通知(在何時):你希望這個切面什么時候執(zhí)行?“通知”指定了你想要執(zhí)行切面代碼的一些常見的時刻,比如“before”、“after”、“around”、“whenThrowing”等等。反過來,它們指的是與代碼執(zhí)行相關(guān)的時間點。對于在代碼執(zhí)行后引用的部分,這個切面將攔截返回值,并可能在需要時覆蓋它。

切點(在何地):他們引用了你想要注入的切面在你的目標代碼中的位置。理論上,你可以明確指定在目標代碼中的任何位置去執(zhí)行切面代碼。實際上這并不現(xiàn)實,但你可以潛在地指定,比如:“我的對象中的所有方法”,或者“僅僅是這一個特定方法”,或者我們甚至可以使用“所有以get_開頭的方法”之類的內(nèi)容。

有了這些解釋,你會發(fā)現(xiàn)創(chuàng)建一個基于AOP的庫來向現(xiàn)有的基于OOP的業(yè)務(wù)邏輯(舉個例子)添加日志邏輯是相對容易的。你所要做的就是用一個自定義函數(shù)替換目標對象現(xiàn)有的匹配方法,該自定義函數(shù)會在適當?shù)臅r間點添加切面邏輯,然后再調(diào)用原有的方法。

因為我是一個視覺學(xué)習(xí)者,所以我認為,展示一個基本的例子說明如何實現(xiàn)一種切面方法來添加基于AOP的行為將是個漫長的過程。

下面的示例將闡明實現(xiàn)它有多容易以及它給你的代碼帶來的好處。

`/**用于獲取一個對象中所有方法的幫助函數(shù)*/constgetMethods=(obj)=Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(item=typeofobj[item]==='function')

/**將原始方法替換為自定義函數(shù),該函數(shù)將在通知指示時調(diào)用我們的切面*/functionreplaceMethod(target,methodName,aspect,advice){constoriginalCode=target[methodName]target[methodName]=(...args)={if(["before","around"].includes(advice)){aspect.apply(target,args)}constreturnedValue=originalCode.apply(target,args)if(["after","around"].includes(advice)){aspect.apply(target,args)}if("afterReturning"==advice){returnaspect.apply(target,[returnedValue])}else{returnreturnedValue

}}}

module.exports={//導(dǎo)出的主要方法:在需要的時間和位置將切面注入目標inject:function(target,aspect,advice,pointcut,method=null){if(pointcut=="method"){if(method!=null){replaceMethod(target,method,aspect,advice)

}else{thrownewError("Tryintoaddanaspecttoamethod,butnomethodspecified")}}if(pointcut=="methods"){constmethods=getMethods(target)methods.forEach(m={replaceMethod(target,m,aspect,advice)

})}}}`

非常簡單,正如我提到的,上面的代碼并沒有涵蓋所有的用例,但是它應(yīng)該足以涵蓋下一個示例。

但是在我們往下看之前,注意一下這個replaceMethod函數(shù),這就是“魔法”生效的地方。它能夠創(chuàng)建新函數(shù),也可以決定我們何時調(diào)用我們的切面以及如何處理它的返回值。

接下來說明這個庫的用法:

`constAOP=require("./aop.js")

classMyBussinessLogic{

add(a,b){

console.log("Callingadd")

returna+b

concat(a,b){

console.log("Callingconcat")

returna+b

power(a,b){

console.log("Callingpower")

returna**b

consto=newMyBussinessLogic()

functionloggingAspect(...args){console.log("==Callingtheloggerfunction==")console.log("Argumentsreceived:"+args)}

functionprintTypeOfReturnedValueAspect(value){console.log("Returnedtype:"+typeofvalue)}

AOP.inject(o,loggingAspect,"before","methods")AOP.inject(o,printTypeOfReturnedValueAspect,"afterReturning","methods")

o.add(2,2)o.concat("hello","goodbye")o.power(2,3)`

這只是一個包含三個方法的基本對象,沒什么特別的。我們想要去注入兩個通用的切面,一個用于記錄接收到的屬性,另一個用于分析他們的返回值并記錄他們的類型。兩個切面,兩行代碼(并不需要六行代碼)。

這個示例到這里就結(jié)束了,這里是你將得到的輸出:

/f18ef187f4acddab8df097c8aa4521d632e17759bc1c0831a22ada934388d7b5/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f323030302f312a394b5a42774f6262714145754a4176314757537279672e706e67

AOP的優(yōu)點

在知道了AOP的概念及用途后,也行你已經(jīng)猜到了為什么人們會想要使用面向切面編程,不過還是讓我們做一個快速匯總吧:

封裝橫切關(guān)注點的好方法。我非常喜歡封裝,因為它意味著更容易閱讀和維護可以在整個項目中重復(fù)使用的代碼。

靈活的邏輯。在注入切面時,圍繞通知和切入點實現(xiàn)的邏輯可以為你提供很大的靈活性。反之這又有助于你動態(tài)地打開和關(guān)閉代碼邏輯的不同切面(有意的雙關(guān))。

跨項目重復(fù)使用切面。你可以將切面視為組件,即可以在任何地方運行的小的、解耦的代碼片段。如果你正確地編寫了切面代碼,就可以輕松地在不同的項目中共享它們。

AOP的主要問題

因為并非每件事都是完美的,這種范式遭到了一些批評者的反對。

他們提出的主要問題是,它的主要的優(yōu)勢實際上隱藏了代碼邏輯和復(fù)雜性,在不太清楚的情況下可能會產(chǎn)生副作用。

如果你仔細想想,他們說的有一定道理,AOP給了你很多能力,可以將無關(guān)的行為添加到現(xiàn)有的方法中,甚至可以替換它們的整個邏輯。當然,這可能不是引入此范式的確切原因,而且它肯定不是我上面提供的示例的意圖。

然而,它確實可以讓你去做任何你想做的事情,再加上缺乏對良好編程實踐的理解,可能會導(dǎo)致非常大的混亂。

為了不讓自己聽起來太老套,我轉(zhuǎn)述一下UncleBen的話:

能力越大,責(zé)任越大

如果你想正確地使用AOP,那么就必須理解軟件開發(fā)的最佳實踐。

在我看來,僅僅因為你使用這個工具之后可能會帶來很大的損害,并不足以說明這個工具就是不好的,因為它也會帶來很多的好處(即你可以將很多常見的邏輯提取到一個集中的位置,并可以在你需要的任何地方用一行代碼注入它)。對我來說,這是一個強大的工具,值得學(xué)習(xí),也絕對值得使用。

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論