摘要:使用面向切面編程來(lái)快速的創(chuàng)建職責(zé)鏈的具體概念可以參考裝飾者模式實(shí)現(xiàn)職責(zé)鏈簡(jiǎn)單又巧妙,但這種把函數(shù)疊在一起的方式,同時(shí)也疊加了函數(shù)的作用域,如果鏈條太長(zhǎng)的話(huà),也會(huì)對(duì)性能造成太大的影響。在開(kāi)發(fā)中,職責(zé)鏈模式是最容易被忽視的模式之一。
聲明:這個(gè)系列為閱讀《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》 ----曾探@著一書(shū)的讀書(shū)筆記
1.職責(zé)鏈模式的定義
2.
2.1 簡(jiǎn)單職責(zé)鏈模式
2.2職責(zé)鏈重構(gòu)上面的代碼
2.3靈活的拆分職責(zé)鏈節(jié)點(diǎn)
3.異步職責(zé)鏈
4.職責(zé)鏈模式的優(yōu)缺點(diǎn):
5.使用AOP(面向切面編程)來(lái)快速的創(chuàng)建職責(zé)鏈
總結(jié):
1.職責(zé)鏈模式的定義2. 2.1 簡(jiǎn)單職責(zé)鏈模式使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,將這些對(duì)象連成一條鏈,并沿著這條鏈傳遞該請(qǐng)求,直到有一個(gè)對(duì)象處理它為止。
故事背景:用戶(hù)可以支付定金購(gòu)買(mǎi)手機(jī),并且可以獲得優(yōu)惠券。沒(méi)有支付定金的就是普通用戶(hù),進(jìn)入普通購(gòu)買(mǎi)模式,沒(méi)有優(yōu)惠券,且?guī)齑娌蛔愕那闆r下不一定能夠買(mǎi)到手機(jī)。
/** * * @param orderType 訂單類(lèi)型 * @param pay 用戶(hù)是否已經(jīng)支付過(guò)定金 true or false * @param stock 表示手機(jī)的庫(kù)存量 */ var order = function (orderType, pay, stock){ if (orderType === 1) { if (pay === true) { console.log("500定金預(yù)購(gòu),得到100元優(yōu)惠券"); } else { if (stock > 0) { console.log("普通購(gòu)買(mǎi),沒(méi)有優(yōu)惠券"); } else { console.log("手機(jī)庫(kù)存不足"); } } } else if (orderType === 2) { if (pay === true) { console.log("200定金預(yù)購(gòu),得到50元優(yōu)惠券"); } else { if (stock > 0) { console.log("普通購(gòu)買(mǎi),沒(méi)有優(yōu)惠券"); } else { console.log("手機(jī)庫(kù)存不足"); } } } else if (orderType === 3) { if (stock > 0) { console.log("普通購(gòu)買(mǎi),沒(méi)有優(yōu)惠券"); } else { console.log("手機(jī)庫(kù)存不足"); } } };2.2職責(zé)鏈重構(gòu)上面的代碼
主要通過(guò)拆分功能語(yǔ)句,來(lái)使用職責(zé)鏈重構(gòu):
//500元訂單 var order500 = function (orderType, pay, stock){ if (orderType === 1 && pay === true) { console.log("500定金預(yù)購(gòu),得到100元優(yōu)惠券"); } else { order200(orderType, pay, stock); //將請(qǐng)求傳遞給200 } }; //200元訂單 var order200 = function (orderType, pay, stock){ if (orderType === 2 && pay === true) { console.log("200定金預(yù)購(gòu),得到50元優(yōu)惠券"); } else { order(orderType, pay, stock); } }; //普通購(gòu)買(mǎi)訂單 var order = function (orderType, pay, stock){ if (stock>0) { console.log("普通購(gòu)買(mǎi),沒(méi)有優(yōu)惠券"); } else { console.log("手機(jī)庫(kù)存不足"); } }; //測(cè)試調(diào)用 order500(1,true,500); order500(3,false,0);
總結(jié):
上面的代碼違反了開(kāi)放-封閉的原則,請(qǐng)求在鏈條中傳遞的順序非常僵硬,傳遞請(qǐng)求的代碼被耦合在了業(yè)務(wù)函數(shù)中:
var order500 = function (orderType, pay, stock){ if (orderType === 1 && pay === true) { console.log("500定金預(yù)購(gòu),得到100元優(yōu)惠券"); } else { order200(orderType, pay, stock); //將請(qǐng)求傳遞給200 } };2.3靈活的拆分職責(zé)鏈節(jié)點(diǎn)
為什么要拆分職責(zé)鏈的節(jié)點(diǎn),因?yàn)槟程煨枰砑有碌穆氊?zé),就需要修改業(yè)務(wù)代碼(要修改的話(huà),就需要先去了解他,熟悉它,花費(fèi)大量的時(shí)間)。這顯然不是每一個(gè)人所需要的。
//500元訂單 var order500 = function (orderType, pay, stock){ if (orderType === 1 && pay === true) { console.log("500定金預(yù)購(gòu),得到100元優(yōu)惠券"); } else { return "nextSuccessor"; } }; //200元訂單 var order200 = function (orderType, pay, stock){ if (orderType === 2 && pay === true) { console.log("200定金預(yù)購(gòu),得到50元優(yōu)惠券"); } else { return "nextSuccessor"; } }; //普通購(gòu)買(mǎi)訂單 var order = function (orderType, pay, stock){ if (stock>0) { console.log("普通購(gòu)買(mǎi),沒(méi)有優(yōu)惠券"); } else { console.log("手機(jī)庫(kù)存不足"); } }; var Chain=function (fn){ this.fn=fn; this.successor=null; }; Chain.prototype.setNextSuccessor=function (successor){ return this.successor=successor; }; Chain.prototype.passRequest=function(){ var ret= this.fn.apply(this,arguments); if(ret==="nextSuccessor"){ return this.successor && this.successor.passRequest.apply(this.successor,arguments); } return ret; }; var chainOrder500=new Chain(order500()); var chainOrder200=new Chain(order200()); var chainOrderNormal=new Chain(order()); chainOrder500.setNextSuccessor(chainOrder200); chainOrder200.setNextSuccessor(chainOrderNormal); chainOrder500.passRequest(1,true,500); chainOrder500.passRequest(2,true,500); chainOrder500.passRequest(1,false,0);
加入某天網(wǎng)站添加了300元定金購(gòu)買(mǎi)的職責(zé),我只需要添加特定的節(jié)點(diǎn)就可以了:
//300元訂單 var order300=function (){ }; var chainOrder300=new Chain(order300()); chainOrder500.setNextSuccessor(chainOrder300); chainOrder500.setNextSuccessor(chainOrder200);
這樣的話(huà)只需要編寫(xiě)簡(jiǎn)單的功能函數(shù),改變職責(zé)鏈中的相關(guān)節(jié)點(diǎn)的順序即可。
3.異步職責(zé)鏈上面的職責(zé)鏈代碼中,每個(gè)節(jié)點(diǎn)函數(shù)同步返回一個(gè)特定的值nextSuccessor,來(lái)表示是否把請(qǐng)求傳遞給下一個(gè)節(jié)點(diǎn)。而現(xiàn)實(shí)開(kāi)發(fā)中會(huì)遇到一些異步的問(wèn)題,比如在一個(gè)節(jié)點(diǎn)中發(fā)起一個(gè)ajax異步請(qǐng)求,異步請(qǐng)求的結(jié)果才能決定是否繼續(xù)在職責(zé)鏈中passRequest。
可以給Chain類(lèi)添加一個(gè)原型方法Chain.prototype.next,表示手動(dòng)傳遞請(qǐng)求給職責(zé)鏈中的下一個(gè)節(jié)點(diǎn):
Chain.prototype.next=function(){ return this.successor && this.successor.passRequest.apply(this.successor,arguments); }; //異步職責(zé)鏈的例子 var fn1=new Chain(function (){ console.log(1); return "nextSuccessor"; }); var fn2=new Chain(function (){ console.log(2); var self=this; setTimeout(function (){ self.next(); },1000); }); var fn3=new Chain(function (){ console.log(3); }); fn1.setNextSuccessor(fn2).setNextSuccessor(fn3); fn1.passRequest();4.職責(zé)鏈模式的優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
職責(zé)鏈最大的優(yōu)點(diǎn)就是解耦了請(qǐng)求發(fā)送者和N個(gè)接收者之間的復(fù)雜關(guān)系。
職責(zé)鏈可以手動(dòng)指定起始節(jié)點(diǎn),請(qǐng)求并不是非得從鏈中的第一個(gè)節(jié)點(diǎn)開(kāi)始傳遞。
缺點(diǎn):
不能保證某個(gè)請(qǐng)求一定會(huì)被鏈中的節(jié)點(diǎn)處理,這種情況可以在鏈尾增加一個(gè)保底的接受者節(jié)點(diǎn)來(lái)處理這種即將離開(kāi)鏈尾的請(qǐng)求。
使程序中多了很多節(jié)點(diǎn)對(duì)象,可能再一次請(qǐng)求的過(guò)程中,大部分的節(jié)點(diǎn)并沒(méi)有起到實(shí)質(zhì)性的作用。他們的作用僅僅是讓請(qǐng)求傳遞下去,從性能當(dāng)面考慮,要避免過(guò)長(zhǎng)的職責(zé)鏈到來(lái)的性能損耗。
5.使用AOP(面向切面編程)來(lái)快速的創(chuàng)建職責(zé)鏈AOP的具體概念可以參考裝飾者模式
Function.prototype.after=function(fn){ var self=this; return function(){ var ret=self.apply(this,arguments); if(ret==="nextSuccessor"){ return fn.apply(this,arguments); } return ret; } }; var order=order500yuan.after(order200yuan).after(orderNormal); order(1,true,500); order(1,false,500);
AOP實(shí)現(xiàn)職責(zé)鏈簡(jiǎn)單又巧妙,但這種把函數(shù)疊在一起的方式,同時(shí)也疊加了函數(shù)的作用域,如果鏈條太長(zhǎng)的話(huà),也會(huì)對(duì)性能造成太大的影響。
總結(jié):職責(zé)鏈模式最大的優(yōu)點(diǎn):請(qǐng)求發(fā)送者只需要知道鏈中的第一個(gè)節(jié)點(diǎn),從而弱化了發(fā)送者和一組接收者之前的強(qiáng)聯(lián)系。
在JavaScript開(kāi)發(fā)中,職責(zé)鏈模式是最容易被忽視的模式之一。但是只要運(yùn)用得當(dāng),職責(zé)鏈模式可以很好的幫助我們管理代碼,降低發(fā)起請(qǐng)求的對(duì)象和處理請(qǐng)求的對(duì)象之間的耦合性。且職責(zé)鏈中節(jié)點(diǎn)的數(shù)量和數(shù)序是可以自由變化的??梢栽谶\(yùn)行時(shí)決定鏈中包含哪些節(jié)點(diǎn)。
無(wú)論是作用域鏈,原型鏈,還是DOM節(jié)點(diǎn)中的事件冒泡,我們都能從中找到職責(zé)鏈模式的影子。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/90839.html
摘要:代理模式,迭代器模式,單例模式,裝飾者模式最少知識(shí)原則一個(gè)軟件實(shí)體應(yīng)當(dāng)盡可能少地與其他實(shí)體發(fā)生相互作用。迭代器模式可以將迭代的過(guò)程從業(yè)務(wù)邏輯中分離出來(lái),在使用迭代器模式之后,即不用關(guān)心對(duì)象內(nèi)部構(gòu)造也可以按順序訪問(wèn)其中的每個(gè)元素。 接手項(xiàng)目越來(lái)越復(fù)雜的時(shí)候,有時(shí)寫(xiě)完一段代碼,總感覺(jué)代碼還有優(yōu)化的空間,卻不知道從何處去下手。設(shè)計(jì)模式主要目的是提升代碼可擴(kuò)展性以及可閱讀性。 本文主要以例子的...
摘要:裝飾者模式定義裝飾者模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 裝飾者模式 定義 : 裝飾者(decorator)模式能夠在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)像動(dòng)態(tài)的添加職責(zé)。與繼承相比,裝飾者是一種更輕便靈活的做法。 在不改變對(duì)象自身的基礎(chǔ)上,在程序運(yùn)行期間給對(duì)象動(dòng)態(tài)地添加一些額外職責(zé) 特點(diǎn) : 可以動(dòng)態(tài)的...
摘要:訂閱模式的一個(gè)典型的應(yīng)用就是后面會(huì)寫(xiě)一篇相關(guān)的讀書(shū)筆記。享元模式享元模式的核心思想是對(duì)象復(fù)用,減少對(duì)象數(shù)量,減少內(nèi)存開(kāi)銷(xiāo)。適配器模式對(duì)目標(biāo)函數(shù)進(jìn)行數(shù)據(jù)參數(shù)轉(zhuǎn)化,使其符合目標(biāo)函數(shù)所需要的格式。 設(shè)計(jì)模式 單例模式 JS的單例模式有別于傳統(tǒng)面向?qū)ο笳Z(yǔ)言的單例模式,js作為一門(mén)無(wú)類(lèi)的語(yǔ)言。使用全局變量的模式來(lái)實(shí)現(xiàn)單例模式思想。js里面的單例又分為普通單例和惰性單例,惰性單例指的是只有這個(gè)實(shí)例...
摘要:前言設(shè)計(jì)模式幾十種,閱讀了設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐這本書(shū)后,個(gè)人感覺(jué)就是圍繞對(duì)象來(lái)設(shè)計(jì)的,發(fā)現(xiàn)日常寫(xiě)代碼能用上的并不多,下面是常用的幾種設(shè)計(jì)模式。前端服務(wù)端可以參考我的另一個(gè)倉(cāng)庫(kù)地址,一個(gè)簡(jiǎn)單的實(shí)時(shí)聊天參考來(lái)自設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐讀書(shū)筆記 前言 設(shè)計(jì)模式幾十種,閱讀了《JavaScript設(shè)計(jì)模式與開(kāi)發(fā)實(shí)踐》這本書(shū)后,個(gè)人感覺(jué)js就是圍繞對(duì)象來(lái)設(shè)計(jì)的,發(fā)現(xiàn)日常寫(xiě)代碼能用上的并不多,下面是常用的...
摘要:想一想,這個(gè)和我們的迭代器模式有著異曲同工的妙處,迭代器模式同樣也是遍歷選出最優(yōu)解,但是相比而言,職責(zé)鏈模式的直觀性個(gè)書(shū)寫(xiě)的幸福感是遠(yuǎn)遠(yuǎn)超過(guò)迭代器模式的。 職責(zé)鏈模式其實(shí)很好理解,由于一個(gè)鏈字出賣(mài)了它的靈魂。我們可以從這個(gè)字得到很大的提示。首先這個(gè)模式一定有傳遞性,而且,節(jié)點(diǎn)是可以重復(fù)拼接的,并且每個(gè)節(jié)點(diǎn)都具有一定的過(guò)濾功能,一定的職責(zé)。 是不是想起了組合模式里的一些內(nèi)容呢? 是的,他...
閱讀 2619·2023-04-26 00:57
閱讀 974·2021-11-25 09:43
閱讀 2287·2021-11-11 16:55
閱讀 2364·2019-08-30 15:53
閱讀 3656·2019-08-30 15:52
閱讀 1530·2019-08-30 14:10
閱讀 3435·2019-08-30 13:22
閱讀 1265·2019-08-29 11:18