職責鏈模式的定義是:使多個對象都有機會處理請求望迎,從而避免請求的發(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ù)的作用域该编,如果鏈條太長的話,也會對性能有較大的影響构灸。
我的理解:職責鏈模式算是迭代器模式的一個延伸上渴,里面的思想與迭代器模式有些相似之處岸梨。迭代器是把隊列每個元素作為輸入喜颁,然后用戶自己定義處理邏輯,而職責鏈是用戶指定多個處理邏輯曹阔,處理同一個輸入半开,只有滿足條件的那個處理邏輯才能真正輸出,而其他處理邏輯只是把輸入傳遞給下一個處理邏輯赃份。