這是我參與更文挑戰的第4天,活動詳情查看: 更文挑戰javascript
職責鏈模式就是當一個對象 a
,有多種可能的請求對象 b
、c
、d
、e
時,咱們爲 b
、c
、d
、e
分別定義一個職責,組成一條職責鏈,這樣 a
只須要找到 b
發起請求,而後沿着職責鏈繼續請求,直到找到一個對象來處理 a
。java
女孩子們都喜歡結伴吃飯,我如今要找一我的一塊兒吃飯,代碼以下: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(`哎呀,我要一我的吃晚飯啦`)
}
}
複製代碼
因爲 astrid
、brooke
、calliope
吃晚飯的要求不一樣,我須要一個個去發起晚餐請求,直到找到答應和我一塊兒吃晚飯的人。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
方法,請繼續往下看。函數
下週就是 618,電商網站免不得會推出商品預售活動,假設在 618 以前,預付 500 定金,可得到 100 元優惠券,預付 200 元定金,可得到 50 優惠券,未付定金則無優惠券。618 當天的購買事件以下:
先上代碼。
本文代碼僅舉例說明,和業務無關。
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
判斷,不利於維護。
定義一個職責類 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)
複製代碼
上述代碼將 chainOrder500
和 chainOrder200
組成一條職責鏈,無論用戶是哪一種類型,都只須要向 chainOrder500
發起請求,若是 chainOrder500
沒法處理請求,就會繼續沿着職責鏈發起請求,直到找到能處理請求的職責方法。
經過職責鏈模式,解耦了請求發送者和多個接收者之間的複雜關係,再也不須要知道具體哪一個接收者來接收發送的請求,只須要向職責鏈的第一個階段發起請求。
職責鏈模式,幫助咱們管理代碼,下降發起請求和接收請求對象之間的耦合。
職責鏈模式中的節點數量和順序是能夠自由變更的,能夠在運行時決定鏈中包含哪些節點。
可經過 github源碼 進行實操練習。
但願能對你有所幫助,感謝閱讀~別忘了點個贊鼓勵一下我哦,筆芯❤️
· 往期精彩 ·