使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象都练成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
如图所示:
请求→A→B→C→D
再来一个更形象的比喻,读书的时候假设你坐在前面,要在上课时告诉后排一些事情,这时候你可能会选择写一张小纸条,小纸条就会陆续的被向后传递。
从上面的例子中,我们可以看到职责链的优点:请求发送者只需要知道链中的第一个节点,从而弱化了发送者和一组接收者之间的强联系。
需求:一个售卖手机的电商网站,交纳500定金和200定金和没交定金的有不同的优惠状况。
我们刚开始可能会这么写:
// orderType: 订单类型(普通用户或定金用户),1为500元定金用户,2为200,3为普通用户
// pay:表示是否已支付定金,true或false
// stock:表示当前用于普通购买的手机库存数量,已支付过定金的用户不受此限制。
var order = function (orderType, pay, stock) { if (orderType === 1) { //500元定金购买模式 if (pay === true) { console.log('500元定金预定,已获得100元优惠券'); }else { //未支付定金,降级到普通购买模式 if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('库存不足'); } } } else if (orderType === 2) { if (pay === true) { console.log('200元定金预定,已获得50元优惠券'); }else { //未支付定金,降级到普通购买模式 if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('库存不足'); } } } else if (orderType === 3) { if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('库存不足'); } } }; order(1, true, 500);
以上代码虽然保证了可以用的状态,但是只是能用,如果要修改就会很麻烦,而且阅读体验也不是很好,所以我们做一点优化
var order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) { //500元定金购买模式
console.log(‘500元定金预定,已获得100元优惠券’);
} else {
order200 (orderType, pay, stock); //将请求传递给200元订单
}
};
var order200 = function (orderType, pay, stock) { if (orderType === 2 && pay === true) { //200元定金购买模式 console.log('200元定金预定,已获得50元优惠券'); } else { orderNormal (orderType, pay, stock); //将请求传递给普通订单 } }; var orderNormal = function (orderType, pay, stock) { if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('库存不足'); } }; order500 (1, true, 500);
虽然这有了小小进步,不过请求在链条中的传递依然很僵硬,传递请求的代码被耦合在了业务函数中,这显然是违反开放-封闭原则的,例如如果有一天我们要增加300元预定或者200元预定,意味着就必须改动这些业务函数的内部,就像一根根环环相扣的死结链条。
var order500 = function (orderType, pay, stock) {
if (orderType === 1 && pay === true) { //500元定金购买模式
console.log(‘500元定金预定,已获得100元优惠券’);
} else {
return ‘nextSuccessor’; //我不知道下一个节点是谁,反正向后传递就好了
}
};
var order200 = function (orderType, pay, stock) { if (orderType === 2 && pay === true) { //200元定金购买模式 console.log('200元定金预定,已获得50元优惠券'); } else { return 'nextSuccessor'; } }; var orderNormal = function (orderType, pay, stock) { if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('库存不足'); } }; //Chain.prototype.setNextSuccessor 指定在链中的下一个节点 //Chain.prototype.passRequest 传递请求给某个节点 var Chain = function(fn) { this.fn = fn; this.successor = null; }; Chain.prototype.setNextSuccessor = function(successor) { return this.successor = successor; }; Chain.prototype.passRequest = function(successor) { var ret = this.fn.apply(this, arguments); if (ret === 'nextSuccessor') { return this.successor && this.successor.passRequest.apply(this.successor, arguments); } return ret; }; var chainOrder500 = new Chain(order500); var chainOrder200 = new Chain(order200); var chainOrderNormal = new Chain(orderNormal); chainOrder500.passRequest(1, true, 500); //500定金优惠100 chainOrder200.passRequest(2, true, 500); //200定金优惠50 chainOrderNormal.passRequest(3, true, 500); //普通购买无优惠券 chainOrderNormal.passRequest(1, false, 0); //库存不足