解决请求发送者和接受者之间的耦合,通过职责链上多个对象分解请求流程,实现请求在多个对象之间的传递,直到最后一个对象完成请求的处理。
职责链模式的优点是:请求发送者只需要直到链中的第一个节点,从而解耦了发送者和一组接收者之间的强联系。此外,使用了职责链模式之后,链中的节点对象可以灵活地拆分重组,增加或者删除 一个节点,以及改变节点在链中的位置都是轻而易举的。
职责链模式的缺点是:首先不能保证某个请求一定会被链中的某个节点处理,这种情况系下可以在链尾增加一个保底的接受者节点来处理这种即将离开链尾的请求。其次,职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分的节点并没有起到实质性的作用,从性能的角度考虑,应当避免过长的职责链带来的性能损耗。
假设有这么一种场景:一个售卖手机的电商网站,经过分别交纳 500 元定金和 200 元定金的两轮预订之后(订单在此时已经生成),现在进入了正式购买阶段。
公司针对支付过定金的客户有一定的优惠,正式购买之后,已经支付过 500 元定金的用户会收到 100 元优惠券,200 元定金的用户可以收到 50 元优惠券,没有支付过定金的只能进入普通购买方式,也就是没有优惠券。相关的字段有这么几种:
oederType
: 订单类型,为 1 代表 500 元定金用户,2 代表 200 元定金用户,3 为普通购买用户;
//职责链模式
var order500 = function(orderType, pay, stock) {
if (orderType == 1 && pay === true) {
console.log('500元定金预约,得到100元优惠券');
} else {
return 'nextSuccessor';
}
};
var order200 = function(orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('200元定金预约,得到50优惠券');
} else {
return 'nextSuccessor';
}
};
var orderNormal = function(orderType, pay, stock) {
if (stock > 0) {
console.log('普通购买,无优惠券');
} else {
return 'nextSuccessor';
}
};
接下来需要把函数包装进职责链节点:
//职责链包装
var Chain = function(fn) {
this.fn = fn;
this.nextSuccessor = null;
};
Chain.prototype.setNextSuccessor = function(successor) {
return (this.nextSuccessor = successor);
};
Chain.prototype.passRequest = function() {
var ret = this.fn.apply(this, arguments);
if (ret == 'nextSuccessor') {
//console.log(this.nextSuccessor.fn.name);
return (
this.nextSuccessor &&
this.nextSuccessor.passRequest.apply(this.nextSuccessor, arguments)
); //启动这一步启动递归了
}
return ret;
};
//测试
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
chainOrder500.setNextSuccessor(chainOrder200);
chainOrder200.setNextSuccessor(chainOrderNormal);
//将请求传递给第一个节点即可
chainOrder500.passRequest(1, true, 100); //输出 500元定金,得到100元优惠券
chainOrder500.passRequest(2, true, 100); //输出200元定金,得到50元优惠券
chainOrder500.passRequest(1, false, 0); //输出 手机库存不足