- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > web開(kāi)發(fā) > JavaScript >
- JavaScript中的AOP編程的基本實(shí)現
AOP(面向切面編程)的主要作用是把一些跟核心業(yè)務(wù)邏輯模塊無(wú)關(guān)的功能抽離出來(lái),這些跟業(yè)務(wù)邏輯無(wú)關(guān)的功能通常包括日志統計、安全控制、異常處理等。把這些功能抽離出來(lái)之后, 再通過(guò)“動(dòng)態(tài)織入”的方式摻入業(yè)務(wù)邏輯模塊中。
面向切面編程給我們提供了一個(gè)方法,讓我們可以在不修改目標邏輯的情況下,將代碼注入到現有的函數或對象中。
雖然不是必須的,但注入的代碼意味著(zhù)具有橫切關(guān)注點(diǎn),比如添加日志功能、調試元數據或其它不太通用的但可以注入額外的行為,而不影響原始代碼的內容。
給你舉一個(gè)合適的例子,假設你已經(jīng)寫(xiě)好了業(yè)務(wù)邏輯,但是現在你意識到?jīng)]有添加日志代碼。通常的方法是將日志邏輯集中到一個(gè)新的模塊中,然后逐個(gè)函數添加日志信息。
然而,如果你可以獲取同一個(gè)日志程序,在你想要記錄的每個(gè)方法執行過(guò)程中的特定節點(diǎn),只需一行代碼就可將程序注入,那么這肯定會(huì )給你帶來(lái)很多便利。難道不是嗎?
為了使上面的定義更形式化一點(diǎn),讓我們以日志程序為例,介紹有關(guān) AOP 的三個(gè)概念。如果你決定進(jìn)一步研究這個(gè)范式,這些將對你有所幫助:
有了這些解釋?zhuān)銜?huì )發(fā)現創(chuàng )建一個(gè)基于 AOP 的庫來(lái)向現有的基于 OOP 的業(yè)務(wù)邏輯(舉個(gè)例子)添加日志邏輯是相對容易的。你所要做的就是用一個(gè)自定義函數替換目標對象現有的匹配方法,該自定義函數會(huì )在適當的時(shí)間點(diǎn)添加切面邏輯,然后再調用原有的方法。
因為我是一個(gè)視覺(jué)學(xué)習者,所以我認為,展示一個(gè)基本的例子說(shuō)明如何實(shí)現一種 切面
方法來(lái)添加基于 AOP 的行為將是個(gè)漫長(cháng)的過(guò)程。
下面的示例將闡明實(shí)現它有多容易以及它給你的代碼帶來(lái)的好處。
`/** 用于獲取一個(gè)對象中所有方法的幫助函數 */ const getMethods = (obj) => Object.getOwnPropertyNames(Object.getPrototypeOf(obj)).filter(item => typeof obj[item] === 'function') /** 將原始方法替換為自定義函數,該函數將在通知指示時(shí)調用我們的切面 */ function replaceMethod(target, methodName, aspect, advice) { const originalCode = target[methodName] target[methodName] = (...args) => { if(["before", "around"].includes(advice)) { aspect.apply(target, args) } const returnedValue = originalCode.apply(target, args) if(["after", "around"].includes(advice)) { aspect.apply(target, args) } if("afterReturning" == advice) { return aspect.apply(target, [returnedValue]) } else { return returnedValue } } } module.exports = { // 導出的主要方法:在需要的時(shí)間和位置將切面注入目標 inject: function(target, aspect, advice, pointcut, method = null) { if(pointcut == "method") { if(method != null) { replaceMethod(target, method, aspect, advice) } else { throw new Error("Tryin to add an aspect to a method, but no method specified") } } if(pointcut == "methods") { const methods = getMethods(target) methods.forEach( m => { replaceMethod(target, m, aspect, advice) }) } } }`
非常簡(jiǎn)單,正如我提到的,上面的代碼并沒(méi)有涵蓋所有的用例,但是它應該足以涵蓋下一個(gè)示例。
但是在我們往下看之前,注意一下這個(gè) replaceMethod
函數,這就是“魔法”生效的地方。它能夠創(chuàng )建新函數,也可以決定我們何時(shí)調用我們的切面以及如何處理它的返回值。
接下來(lái)說(shuō)明這個(gè)庫的用法:
`const AOP = require("./aop.js") class MyBussinessLogic { add(a, b) { console.log("Calling add") return a + b } concat(a, b) { console.log("Calling concat") return a + b } power(a, b) { console.log("Calling power") return a ** b } } const o = new MyBussinessLogic() function loggingAspect(...args) { console.log("== Calling the logger function ==") console.log("Arguments received: " + args) } function printTypeOfReturnedValueAspect(value) { console.log("Returned type: " + typeof value) } AOP.inject(o, loggingAspect, "before", "methods") AOP.inject(o, printTypeOfReturnedValueAspect, "afterReturning", "methods") o.add(2,2) o.concat("hello", "goodbye") o.power(2, 3)`
這只是一個(gè)包含三個(gè)方法的基本對象,沒(méi)什么特別的。我們想要去注入兩個(gè)通用的切面,一個(gè)用于記錄接收到的屬性,另一個(gè)用于分析他們的返回值并記錄他們的類(lèi)型。兩個(gè)切面,兩行代碼(并不需要六行代碼)。
這個(gè)示例到這里就結束了,這里是你將得到的輸出:
https://camo.githubusercontent.com/f18ef187f4acddab8df097c8aa4521d632e17759bc1c0831a22ada934388d7b5/68747470733a2f2f63646e2d696d616765732d312e6d656469756d2e636f6d2f6d61782f323030302f312a394b5a42774f6262714145754a4176314757537279672e706e67
在知道了 AOP 的概念及用途后,也行你已經(jīng)猜到了為什么人們會(huì )想要使用面向切面編程,不過(guò)還是讓我們做一個(gè)快速匯總吧:
因為并非每件事都是完美的,這種范式遭到了一些批評者的反對。
他們提出的主要問(wèn)題是,它的主要的優(yōu)勢實(shí)際上隱藏了代碼邏輯和復雜性,在不太清楚的情況下可能會(huì )產(chǎn)生副作用。
如果你仔細想想,他們說(shuō)的有一定道理,AOP 給了你很多能力,可以將無(wú)關(guān)的行為添加到現有的方法中,甚至可以替換它們的整個(gè)邏輯。當然,這可能不是引入此范式的確切原因,而且它肯定不是我上面提供的示例的意圖。
然而,它確實(shí)可以讓你去做任何你想做的事情,再加上缺乏對良好編程實(shí)踐的理解,可能會(huì )導致非常大的混亂。
為了不讓自己聽(tīng)起來(lái)太老套,我轉述一下 Uncle Ben 的話(huà):
能力越大,責任越大
如果你想正確地使用 AOP ,那么就必須理解軟件開(kāi)發(fā)的最佳實(shí)踐。
在我看來(lái),僅僅因為你使用這個(gè)工具之后可能會(huì )帶來(lái)很大的損害,并不足以說(shuō)明這個(gè)工具就是不好的,因為它也會(huì )帶來(lái)很多的好處(即你可以將很多常見(jiàn)的邏輯提取到一個(gè)集中的位置,并可以在你需要的任何地方用一行代碼注入它)。對我來(lái)說(shuō),這是一個(gè)強大的工具,值得學(xué)習,也絕對值得使用。
面向切面編程是 OOP 的完美補充,特別是得益于 JavaScript 的動(dòng)態(tài)特性,我們可以非常容易地實(shí)現它(如這里的代碼演示)。它提供了強大的功能,能夠對大量邏輯進(jìn)行模塊化和解耦,以后甚至可以與其他項目共享這些邏輯。
當然,如果你不正確地使用它,你會(huì )把事情搞得一團糟。但是你絕對可以利用它來(lái)簡(jiǎn)化和清理大量的代碼。這就是我對 AOP 的看法,你呢?你曾經(jīng)聽(tīng)說(shuō)過(guò) AOP 嗎?你以前使用過(guò)它嗎?請在下面留言并分享你的想法!
到此這篇關(guān)于JavaScript中的AOP編程的文章就介紹到這了,更多相關(guān)js AOP編程內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站