第十三章 職責(zé)鏈模式


職責(zé)鏈模式的定義是: 使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求炮温,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,將這些對(duì)象形成一條鏈牵舵,并沿著這條鏈傳遞該請(qǐng)求柒啤,直到有一個(gè)對(duì)象處理它為止。

舉一個(gè)實(shí)際的例子:一款新手機(jī)發(fā)布會(huì)后畸颅,經(jīng)過(guò)了繳納過(guò)500元定金和200元定金的兩輪預(yù)售后担巩,現(xiàn)在到了正式購(gòu)買的階段。 廠家對(duì)交付過(guò)定金的用戶有一定的優(yōu)惠政策:繳納500的用戶没炒,會(huì)得到一張100元的優(yōu)惠券涛癌;繳納200的用戶,會(huì)得到一張30元的優(yōu)惠券送火;沒有交付定金的用戶拳话,沒有優(yōu)惠券,只能進(jìn)入普通購(gòu)買模式种吸,而且在庫(kù)存有限的情況下弃衍,不一定能買得到。

具體的程序?qū)崿F(xiàn)如下:

    var order = function(orderType, pay, stock){
        if(orderType == 1){ // 500元定金模式
            if(pay){
                console.log("500元定金坚俗, 得到100優(yōu)惠券");
            }else{
                if(stock > 0){ // 還有庫(kù)存
                    console.log("普通購(gòu)買 無(wú)優(yōu)惠券");
                }else{
                    console.log("手機(jī)庫(kù)存不足");
                }
            }
        }else if(orderType == 2){ // 100元定金模式
            if(pay){
                console.log("200元定金镜盯, 得到30優(yōu)惠券");
            }else{
                if(stock > 0){ // 還有庫(kù)存
                    console.log("普通購(gòu)買 無(wú)優(yōu)惠券");
                }else{
                    console.log("手機(jī)庫(kù)存不足");
                }
            }
        }else if(orderType == 3){ // 無(wú)定金模式
            if(stock > 0){ // 還有庫(kù)存
                console.log("普通購(gòu)買 無(wú)優(yōu)惠券");
            }else{
                console.log("手機(jī)庫(kù)存不足");
            }
        }
    }

上面的程序難以閱讀而且如要進(jìn)行修改,工作量會(huì)很大坦冠。切合本章的主題形耗,我們引入職責(zé)鏈模式:

    // 500定金
    var order500 = function(orderType, pay, stock){
        if(orderType == 1 && pay){
            console.log("500元定金, 得到100優(yōu)惠券");
        }else{
            order200(orderType, pay, stock); // 此處order500 和 order200的耦合
        }
    }
    
    // 200定金
    var order200 = function(orderType, pay, stock){
        if(orderType == 2 && pay){
            console.log("200元定金辙浑, 得到30優(yōu)惠券");
        }else{
            orderNromal(orderType, pay, stock);// 此處orderNromal 和 order200的耦合
        }
    }
    
    // 普通
    var orderNromal = function(orderType, pay, stock){
        if(stock > 0){ // 還有庫(kù)存
                console.log("普通購(gòu)買 無(wú)優(yōu)惠券");
        }else{
            console.log("手機(jī)庫(kù)存不足");
        }
    }

通過(guò)這種形式個(gè)改造激涤,整個(gè)程序結(jié)構(gòu)就清晰很多。但是其中還是有耦合的問(wèn)題判呕,例如如果加一個(gè)300定金的情況倦踢,那么order500 order200都需要進(jìn)行相應(yīng)邏輯的修改。為此我們進(jìn)一步進(jìn)行程序的優(yōu)化:

    // 500定金
    var order500 = function(orderType, pay, stock){
        if(orderType == 1 && pay){
            console.log("500元定金侠草, 得到100優(yōu)惠券");
        }else{
            return 'nextSuccessor';
        }
    }
    
    // 200定金
    var order200 = function(orderType, pay, stock){
        if(orderType == 2 && pay){
            console.log("200元定金辱挥, 得到30優(yōu)惠券");
        }else{
            return 'nextSuccessor';
        }
    }
    
    // 普通
    var orderNromal = function(orderType, pay, stock){
        if(stock > 0){ // 還有庫(kù)存
                console.log("普通購(gòu)買 無(wú)優(yōu)惠券");
        }else{
            console.log("手機(jī)庫(kù)存不足");
        }
    }
    
    // 構(gòu)造函數(shù)chain
    var Chain = function( fn ){
        this.fn = fn;
        this.successor = null;
    }
    
    // 設(shè)置下一個(gè)執(zhí)行者
    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;
    }
    
    // 把三個(gè)包裝城職責(zé)鏈的節(jié)點(diǎn)
    var chainOrder500 = new Chain(order500);
    var chainOrder200 = new Chain(order200);
    var chainOrderNromal = new Chain(orderNromal);

    // 制定職責(zé)鏈中順序
    chainOrder500.setNextSuccessor(chainOrder200);
    chainOrder200.setNextSuccessor(chainOrderNromal);
    
    // 如下是執(zhí)行
    chainOrder500.passRequest(1, true, 500); // 500元定金, 得到100優(yōu)惠券
    chainOrder500.passRequest(2, true, 500); // 200元定金边涕, 得到30優(yōu)惠券
    
    
    // 借助AOP晤碘,可以把上面的Chain改成更為方便的形式
    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 = order500.after(order200).after(orderNormal);

職責(zé)鏈模式一方面更加清晰的組織我們的代碼褂微;還可以靈活地拆分重組節(jié)點(diǎn)對(duì)象;另外可以手動(dòng)設(shè)定起始節(jié)點(diǎn)园爷,因?yàn)檎?qǐng)求并不一定從最前面一個(gè)節(jié)點(diǎn)開始(比如一個(gè)擠滿人的公交車宠蚂,你從后門上車,把錢傳遞給售票員童社,你的終點(diǎn)是固定的求厕,但是你并不能確定誰(shuí)是第一個(gè)接到你錢的人)。 唯一的問(wèn)題是扰楼,要保證鏈不能太長(zhǎng)呀癣,要不會(huì)引發(fā)性能問(wèn)題。

采用aop實(shí)現(xiàn)職責(zé)鏈?zhǔn)且粋€(gè)非常好的形式~

異步職責(zé)鏈

如果是異步的話弦赖,那么直接返回"nextSuccessor"就沒什么意義了项栏,所以需要給Chain類再增加一個(gè)原型方法:Chain.prototype.next,表示手動(dòng)傳遞請(qǐng)求給職責(zé)鏈中的下一個(gè)節(jié)點(diǎn):

var Chain = function( fn ){
    this.fn = fn;
    this.successor = null;
}

Chain.prototype.setNextSuccessor = function( successor ){
    return this.successor = successor;
}

Chain.prototype.next = function(){
    return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}

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 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();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蹬竖,一起剝皮案震驚了整個(gè)濱河市忘嫉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌案腺,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件康吵,死亡現(xiàn)場(chǎng)離奇詭異劈榨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)晦嵌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門同辣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人惭载,你說(shuō)我怎么就攤上這事旱函。” “怎么了描滔?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵棒妨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我含长,道長(zhǎng)券腔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任拘泞,我火速辦了婚禮纷纫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘陪腌。我一直安慰自己辱魁,他們只是感情好烟瞧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著染簇,像睡著了一般参滴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上剖笙,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天卵洗,我揣著相機(jī)與錄音,去河邊找鬼弥咪。 笑死过蹂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的聚至。 我是一名探鬼主播酷勺,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼扳躬!你這毒婦竟也來(lái)了脆诉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤贷币,失蹤者是張志新(化名)和其女友劉穎击胜,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體役纹,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡偶摔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了促脉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辰斋。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瘸味,靈堂內(nèi)的尸體忽然破棺而出宫仗,到底是詐尸還是另有隱情,我是刑警寧澤旁仿,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布藕夫,位于F島的核電站,受9級(jí)特大地震影響丁逝,放射性物質(zhì)發(fā)生泄漏汁胆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一霜幼、第九天 我趴在偏房一處隱蔽的房頂上張望嫩码。 院中可真熱鬧,春花似錦罪既、人聲如沸铸题。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)丢间。三九已至探熔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烘挫,已是汗流浹背诀艰。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留饮六,地道東北人其垄。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像卤橄,于是被迫代替她去往敵國(guó)和親绿满。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 單例模式 適用場(chǎng)景:可能會(huì)在場(chǎng)景中使用到對(duì)象窟扑,但只有一個(gè)實(shí)例喇颁,加載時(shí)并不主動(dòng)創(chuàng)建,需要時(shí)才創(chuàng)建 最常見的單例模式嚎货,...
    Obeing閱讀 2,067評(píng)論 1 10
  • 工廠模式類似于現(xiàn)實(shí)生活中的工廠可以產(chǎn)生大量相似的商品橘霎,去做同樣的事情,實(shí)現(xiàn)同樣的效果;這時(shí)候需要使用工廠模式殖属。簡(jiǎn)單...
    舟漁行舟閱讀 7,758評(píng)論 2 17
  • 1 場(chǎng)景問(wèn)題# 1.1 申請(qǐng)聚餐費(fèi)用## 來(lái)考慮這樣一個(gè)功能:申請(qǐng)聚餐費(fèi)用的管理茎毁。 很多公司都有這樣的福利,就是項(xiàng)...
    七寸知架構(gòu)閱讀 3,134評(píng)論 3 58
  • 說(shuō)的是閩南人的中秋節(jié)忱辅,其隆重程度大大過(guò)于春節(jié),主要是因?yàn)椴╋炍幕脑催h(yuǎn)流長(zhǎng)谭溉,成了如今閩南地區(qū)獨(dú)具特色的民間...
    天行健與地勢(shì)坤閱讀 535評(píng)論 0 0
  • 一年一度六月七號(hào)高考日墙懂,走過(guò)或者路過(guò)的人高考的人,何曾留下什么遺憾或者感動(dòng)嗎扮念?提起高考损搬,你想到的人或者事又是什么?...
    古月斯人閱讀 256評(píng)論 0 0