職責鏈模式

職責鏈模式的定義是:使多個對象都有機會處理請求望迎,從而避免請求的發(fā)送者和接收者之間的耦合關系搜骡,將這些對象連成一條鏈蚌卤,并沿著這條鏈傳遞該請求稿壁,直到有一個對象處理它為止幽钢。

有這樣一個需求:

假設我們負責一個售賣手機的電商網(wǎng)站,經(jīng)過分別交納500元定金和200元定金的兩輪預定后(訂單已在此時生成)傅是,現(xiàn)在已經(jīng)到了正式購買的階段匪燕。
公司針對支付過定金的用戶有一定的優(yōu)惠政策。在正式購買后落午,已經(jīng)支付過500元定金的用戶會收到100元的商城優(yōu)惠券谎懦,200元定金的用戶可以收到50元的優(yōu)惠券,而之前沒有支付定金的用戶只能進入普通購買模式溃斋,也就是沒有優(yōu)惠券界拦,且在庫存有限的情況下不一定保證能買到。

這個需求寫成代碼就是這樣:

const order = function (orderType, pay, stock) {
  if (orderType === 1) {        // 500元定金購買模式
    if (pay === true) {    // 已支付定金
      console.log('500元定金預購, 得到100優(yōu)惠券');
    } else {    // 未支付定金梗劫,降級到普通購買模式
      if (stock > 0) {    // 用于普通購買的手機還有庫存
        console.log('普通購買, 無優(yōu)惠券');
      } else {
        console.log('手機庫存不足');
      }
    }
  } else if (orderType === 2) {     // 200元定金購買模式
    if (pay === true) {
      console.log('200元定金預購, 得到50優(yōu)惠券');
    } else {
      if (stock > 0) {
        console.log('普通購買, 無優(yōu)惠券');
      } else {
        console.log('手機庫存不足');
      }
    }
  } else if (orderType === 3) {
    if (stock > 0) {
      console.log('普通購買, 無優(yōu)惠券');
    } else {
      console.log('手機庫存不足');
    }
  }
};

order(1, true, 500);  // 輸出: 500元定金預購, 得到100優(yōu)惠券

這樣的代碼有下面的這些問題:

  • 大量重復代碼
  • 所有邏輯都寫在了一個大函數(shù)里面享甸,維護起來很困難
  • 耦合性太強,加入某天需求變更梳侨,比如新增一個300元的優(yōu)惠策略蛉威,那么幾乎要改動整塊代碼

使用職責鏈模式重寫

const order500 = function (orderType, pay, stock) {
  if (orderType === 1 && pay === true) {
    console.log('500元定金預購,得到100優(yōu)惠券')
  } else {
    return 'nextSuccessor'
  }
}

const order200 = function (orderType, pay, stock) {
  if (orderType === 2 && pay === true) {
    console.log('200元定金預購走哺,得到50優(yōu)惠券')
  } else {
    return 'nextSuccessor'
  }
}

const orderNormal = function (orderType, pay, stock) {
  if (stock > 0) {
    console.log('普通購買蚯嫌,無優(yōu)惠券')
  } else {
    console.log('手機庫存不足')
  }
}

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

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

Chain.prototype.passRequest = function () {
  let ret = this.fn.apply(this, arguments)

  if (ret === 'nextSuccessor') {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments)
  }

  return ret
}

const chainOrder500 = new Chain(order500)
const chainOrder200 = new Chain(order200)
const chainOrderNormal = new Chain(orderNormal)

chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrderNormal)

chainOrder500.passRequest( 1, true, 500 );    // 輸出:500元定金預購,得到100優(yōu)惠券
chainOrder500.passRequest( 2, true, 500 );    // 輸出:200元定金預購,得到50優(yōu)惠券
chainOrder500.passRequest( 3, true, 500 );    // 輸出:普通購買择示,無優(yōu)惠券
chainOrder500.passRequest( 1, false, 0 );     // 輸出:手機庫存不足

這樣子束凑,就把各個階段的邏輯解耦開了,如果需要增加300元的優(yōu)惠策略栅盲,也比較容易:

var order300 = function(){
  // 300價位訂單的處理邏輯
};

chainOrder300= new Chain( order300 );
chainOrder500.setNextSuccessor( chainOrder300);
chainOrder300.setNextSuccessor( chainOrder200);

利用js的高級函數(shù)汪诉,還能更加簡潔方便的創(chuàng)建職責鏈:

/* 用AOP實現(xiàn)職責鏈模式 */
Function.prototype.after=function(fn){
  let self=this
  return function(){
    let ret=self.apply(this,arguments)
    if(ret==='nextSuccessor'){
      return fn.apply(this,arguments)
    }

    return ret
  }
}

let order=order500.after(order200).after(orderNormal)

order( 1, true, 500 );    // 輸出:500元定金預購,得到100優(yōu)惠券
order( 2, true, 500 );    // 輸出:200元定金預購谈秫,得到50優(yōu)惠券
order( 1, false, 500 );   // 輸出:普通購買扒寄,無優(yōu)惠券

用AOP來實現(xiàn)職責鏈既簡單又巧妙,但這種把函數(shù)疊在一起的方式拟烫,同時也疊加了函數(shù)的作用域该编,如果鏈條太長的話,也會對性能有較大的影響构灸。

我的理解:職責鏈模式算是迭代器模式的一個延伸上渴,里面的思想與迭代器模式有些相似之處岸梨。迭代器是把隊列每個元素作為輸入喜颁,然后用戶自己定義處理邏輯,而職責鏈是用戶指定多個處理邏輯曹阔,處理同一個輸入半开,只有滿足條件的那個處理邏輯才能真正輸出,而其他處理邏輯只是把輸入傳遞給下一個處理邏輯赃份。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末寂拆,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子抓韩,更是在濱河造成了極大的恐慌纠永,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件谒拴,死亡現(xiàn)場離奇詭異尝江,居然都是意外死亡,警方通過查閱死者的電腦和手機英上,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門炭序,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人苍日,你說我怎么就攤上這事惭聂。” “怎么了相恃?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵辜纲,是天一觀的道長。 經(jīng)常有香客問我,道長耕腾,這世上最難降的妖魔是什么屋摇? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮幽邓,結果婚禮上炮温,老公的妹妹穿的比我還像新娘。我一直安慰自己牵舵,他們只是感情好柒啤,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著畸颅,像睡著了一般担巩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上没炒,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天涛癌,我揣著相機與錄音,去河邊找鬼送火。 笑死拳话,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的种吸。 我是一名探鬼主播弃衍,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坚俗!你這毒婦竟也來了镜盯?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤猖败,失蹤者是張志新(化名)和其女友劉穎速缆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恩闻,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡艺糜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了判呕。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倦踢。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖侠草,靈堂內(nèi)的尸體忽然破棺而出辱挥,到底是詐尸還是另有隱情,我是刑警寧澤边涕,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布晤碘,位于F島的核電站褂微,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏园爷。R本人自食惡果不足惜宠蚂,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望童社。 院中可真熱鬧求厕,春花似錦、人聲如沸扰楼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弦赖。三九已至项栏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蹬竖,已是汗流浹背沼沈。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留币厕,地道東北人列另。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像劈榨,于是被迫代替她去往敵國和親访递。 傳聞我的和親對象是個殘疾皇子晦嵌,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

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

  • 摘自《JavaScript設計模式與開發(fā)實踐》 職責鏈模式的定義是:使多個對象都有機會處理請求同辣,從而避免請求的發(fā)送...
    小小的白菜閱讀 339評論 0 2
  • 概念 ??職責鏈模式使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關系惭载,將這些對象連成一條鏈旱函,...
    小小的開發(fā)人員閱讀 554評論 0 0
  • 職責鏈模式的定義是: 使多個對象都有機會處理請求,從而避免請求的發(fā)送者和接收者之間的耦合關系描滔,將這些對象形成一條鏈...
    狐尼克朱迪閱讀 233評論 0 0
  • 職責鏈模式簡述 職責連是由多個不同的對象組成的棒妨,有發(fā)送者跟接收者,分別負責信息的發(fā)送跟接收含长,其中券腔,鏈中第一個對象是...
    5d18ee6b5b1c閱讀 548評論 0 0
  • 今天我在上個性選修課演講與口才的時候,我拿了14個分數(shù)拘泞,我覺得很開心纷纫,因為,以前我最多只能拿八個陪腌,今天卻拿破了紀錄...
    我是王俊哲閱讀 184評論 1 1