設計模式-看了就會的職責鏈模式(六)

這是我參與更文挑戰的第4天,活動詳情查看: 更文挑戰javascript

1、什麼是職責鏈模式

職責鏈模式就是當一個對象 a,有多種可能的請求對象 bcde 時,咱們爲 bcde 分別定義一個職責,組成一條職責鏈,這樣 a 只須要找到 b 發起請求,而後沿着職責鏈繼續請求,直到找到一個對象來處理 ajava

女孩子們都喜歡結伴吃飯,我如今要找一我的一塊兒吃飯,代碼以下:git

嗯.....女程序員確實是這樣,吃個飯也要寫代碼發請求的。程序員

const [ astrid, brooke, calliope ] = [{
    name: 'astrid',
    requirement: '我要吃湘菜'
},{
    name: 'brooke',
    requirement: '我要找10我的一塊兒吃飯'
},{
    name: 'calliope',
    requirement: '我要和男友一塊兒吃飯'
}]

// 是否知足Astrid的要求
function isSatisfyAstrid (user) { 
    // ... 省略... 
}

// 是否知足Brooke的要求
function isSatisfyBrooke (user) { 
    // ... 省略... 
}

// 是否知足Calliope的要求
function isSatisfyCalliope (user) { 
    // ... 省略... 
}

function eatDinner () {
    if (isSatisfyAstrid()) {
        console.log(`我能夠和 astrid 一塊兒吃晚飯啦`)
    } else if (isSatisfyBrooke()) {
        console.log(`我能夠和 brooke 一塊兒吃晚飯啦`)
    } else if (isSatisfyCalliope()) {
        console.log(`我能夠和 calliope 一塊兒吃晚飯啦`)
    } else {
        console.log(`哎呀,我要一我的吃晚飯啦`)
    }
}
複製代碼

因爲 astridbrookecalliope 吃晚飯的要求不一樣,我須要一個個去發起晚餐請求,直到找到答應和我一塊兒吃晚飯的人。github

在這裏,我假設 astrid 的要求是要吃湘菜,brooke 的要求是要找 10 我的湊一桌一塊兒吃,calliope 的要求是隻想和男友一塊兒吃飯。web

上述代碼用 if-else 的作法很是死板,假如我又多了個朋友 davi,我必須再次修改 eatDinner 方法,違反了開放-封閉原則,不易於維護。設計模式

下面使用職責鏈來優化上述代碼,代碼以下:markdown

// 給每一個人定義一個職責
const chainOrderA = new Chain(isSatisfyAstrid)
const chainOrderB = new Chain(isSatisfyBrooke)
const chainOrderC = new Chain(isSatisfyCalliope)

// 設置一下職責鏈的順序
chainOrderA.setNextSuccessor(chainOrderB)
chainOrderB.setNextSuccessor(chainOrderC)

// 發起請求,這時我只須要向職責鏈上的第一我的請求
function eatDinner () {
    chainOrder.passRequest() // 發起請求
}
複製代碼

將職責做爲轉入 Chain 函數,並經過 setNextSuccessor 定義該職責的下一個職責函數,組成一條 chainOrderA -> chainOrderB -> chainOrderC 職責鏈,這時,我只須要向 astrid 發起請求,若是請求失敗,將會沿着職責鏈繼續請求,直到找到和我一塊兒吃晚飯的人。app

下面將講述在實際場景中怎麼使用職責鏈模式,怎麼實現 Chain 方法,請繼續往下看。函數

2、實際場景

1. 618 預售商品訂單

下週就是 618,電商網站免不得會推出商品預售活動,假設在 618 以前,預付 500 定金,可得到 100 元優惠券,預付 200 元定金,可得到 50 優惠券,未付定金則無優惠券。618 當天的購買事件以下:

1.1 普通作法

先上代碼。

本文代碼僅舉例說明,和業務無關。

const order = function (orderType) {
    if (orderType === 500) {
        console.log('已預付500定金,享有100優惠券')
    } else if (orderType === 200) {
        console.log('已預付200定金,享有50元優惠券')
    } else {
        console.log('未付定金,無優惠')
    }
}

order(500) // '已預付500定金,享有100優惠券'
複製代碼

熟悉的代碼,一長段的 if-else 判斷,不利於維護。

1.2 職責鏈模式

定義一個職責類 Chain

  • 接收一個職責函數 fn 做爲參數;
  • setNextSuccessor 指定該職責的下一個職責函數;
  • passRequest 發起對職責函數 fn 的請求;
    • 若是返回結果是nextSuccesstor,說明請求失敗,繼續請求職責鏈上的下一個職責函數;
    • 若是不是返回 nextSuccesstor,說明找到了接收請求的對象,返回請求結果,再也不繼續執行職責鏈上的下一個職責函數。

代碼以下:

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

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

Chain.prototype.passRequest = function() {
  const ret = this.fn.apply(this, arguments)
  if (ret === 'nextSuccessor') {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments);
  }
  return ret;
};
複製代碼

而後定義職責類實例,經過 setNextSuccessor 組成職責鏈,代碼以下:

const order500 = function (orderType) {
  if (orderType === 500) {
      console.log('已預付500定金,享有100優惠券')
  } else {
    return 'nextSuccessor'
  }
} 

const order200 = function (orderType) {
  if (orderType === 200) {
    console.log('已預付200定金,享有50元優惠券')
  } else {
    return 'nextSuccessor'
  }
} 

const chainOrder500 = new Chain(order500)

const chainOrder200 = new Chain(order200)

chainOrder500.setNextSuccessor(chainOrder200)

chainOrder500.passRequest(200)
複製代碼

上述代碼將 chainOrder500chainOrder200 組成一條職責鏈,無論用戶是哪一種類型,都只須要向 chainOrder500 發起請求,若是 chainOrder500 沒法處理請求,就會繼續沿着職責鏈發起請求,直到找到能處理請求的職責方法。

經過職責鏈模式,解耦了請求發送者和多個接收者之間的複雜關係,再也不須要知道具體哪一個接收者來接收發送的請求,只須要向職責鏈的第一個階段發起請求。

3、小結

職責鏈模式,幫助咱們管理代碼,下降發起請求和接收請求對象之間的耦合。

職責鏈模式中的節點數量和順序是能夠自由變更的,能夠在運行時決定鏈中包含哪些節點。

可經過 github源碼 進行實操練習。

但願能對你有所幫助,感謝閱讀~別忘了點個贊鼓勵一下我哦,筆芯❤️


· 往期精彩 ·

【設計模式-誰沒碰見過幾個單例模式(一)】

【設計模式-什麼是快樂星球,什麼是策略模式(二)】

【設計模式-原來這就是代理模式(三)】

【設計模式-簡單易懂的觀察者模式(四)】

【設計模式-不會吧,不會還有人不知道裝飾器模式吧(五)】

【設計模式-看了就會的職責鏈模式(六)】

相關文章
相關標籤/搜索