職責鏈模式的定義是:使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係,將這些對象連成一條鏈,並沿着這條鏈傳遞該請求,直到有一個對象處理它爲止。 相似於上級分配給給下級任務...ajax
職責鏈模式的最大優勢:請求發送者只須要知道鏈中的第一個節點,從而弱化了發送者和一組接收者之間的強聯繫。咱們只須要將硬幣傳遞個面前的人,直到給到售票員手裏,算是這個任務結束。若是不使用職責鏈模式,我就得先搞清楚誰是售票員,才能把硬幣遞給他。bash
公司針對支付過定金的用戶有必定的優惠政策。app
500元定金的用戶: 會收到100元的商城優惠券,異步
200元定金的用戶: 能夠收到50元的優惠券,函數
普通用戶: 無優惠券,且受到庫存的影響網站
而以前沒有支付定金的用戶自動降級爲普通購買模式,ui
orderType: 1: 500元定金用戶, 2: 200元 , 3: 普通用戶this
isPay: 是否支付過 true: 是, false: 否spa
stock 庫存量prototype
// 訂單函數
function order(orderType, isPay, stock) {
if (orderType === 1) {
if (isPay) {
console.log(' => 500元定金用戶, 獲得100元優惠券',);
} else {
if (stock > 0) {
console.log(' => 普通用戶, 無優惠券',);
}
}
} else if (orderType === 2) {
if (isPay) {
console.log(' => 200元定金用戶, 獲得50元優惠券',);
} else {
if (stock > 0) {
console.log(' => 普通用戶, 無優惠券',);
}
}
} else {
if (stock > 0) {
console.log(' => 普通用戶, 無優惠券',);
} else {
console.log(' => 庫存不足',);
}
}
}
order( 1 , true, 500); // 輸出: 500 元定金預購, 獲得 100 優惠券
複製代碼
上面的實現使用了太多的if else 致使代碼很亂,很難懂, 下面稍微改進一下
function order500(orderType, isPay, stock) {
if (orderType === 1 && isPay) {
console.log(' => 500元定金用戶, 獲得100元優惠券',);
} else {
order200(orderType, isPay, stock); // order200 和 order500 耦合在一塊兒
}
}
function order200(orderType, isPay, stock) {
if (orderType === 2 && isPay) {
console.log(' => 200元定金用戶, 獲得50元優惠券',);
} else {
orderNormal(orderType, isPay, stock);
}
}
function orderNormal(orderType, isPay, stock) {
if (stock > 0) {
console.log(' => 普通用戶, 無優惠券',);
} else {
console.log(' => 庫存不足',);
}
}
複製代碼
可是這個函數有個很明顯的問題, 就是 order500和order200 是牢牢耦合在一塊兒的
function Chain(fn) {
this.fn = fn;
this.next = null;
}
Chain.prototype.setNext = function(next) {
return this.next = next;
}
Chain.prototype.passRequest = function(...args) {
let ret = this.fn.apply(this, next);
if (ret === 'successToNext') { // 自動調用下一個函數
return this.next();
}
return ret;
}
// 手動調用下一個
Chain.prototype.next = function() {
return this.next && this.next.apply(this.next, args);
}
// 生成鏈節點
const ChainOrder500 = new Chain(order500);
const ChainOrder200 = new Chain(order200);
const ChainOrderNormal = new Chain(orderNormal);
// 設置鏈節點執行順序
ChainOrder500.setNext(ChainOrder200).setNext(ChainOrderNormal);
// 傳給第一個節點
chainOrder500.passRequest( 1, true, 500 );
複製代碼
經過改進,咱們能夠自由靈活地增長、移除和修改鏈中的節點順序,假如某天網站運營人員 又想出了支持 300 元定金購買,那咱們就在該鏈中增長一個節點便可
var order300 = function(){ // 具體實現略 };
chainOrder300= new Chain(order300);
chainOrder500.setNext(chainOrder300).setNext(chainOrder200);;
複製代碼
改進以前:
使用職責鏈改進後: 這個請求或者任務 會在往下傳遞, 直到有人接手完成了它,不然會一直傳遞下去,這個相似於 上級給一層層下級傳遞任務。// 異步職責鏈
const fn1 = new Chain(() => {
console.log(' => fn1',);
return 'successToNext';
});
const fn2 = new Chain(() => {
console.log(' => fn2',);
// 發送ajax success callback
setTimeout(() => {
this.next();
}, 2000);
});
const fn3 = new Chain(() => {
console.log('fn3 => ',);
});
fn1.setNext(fn2).setNext(fn3);
fn1.passRequest();
複製代碼
使用了職責鏈模式以後,鏈中的節點對象能夠靈活地拆分重組。增長或者刪除一個節點,或者改變節點在鏈中的位置都是垂手可得的事情。這一點咱們也已經看到,在上面的例子中, 增長一種訂單徹底不須要改動其餘訂單函數中的代碼。
實際上只要運用得當,職責鏈模式能夠很好地幫助咱們管理代碼,下降發起請求的對象和處理請求的對象之間的耦合性。職責鏈中的節點數量和順序是能夠自由變化的,咱們能夠在運行時決定鏈中包含哪些節點。