定义
职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 类似于上级分配给给下级任务...
职责链模式的最大优点:请求发送者只需要知道链中的第一个节点,从而弱化了发送者和一组接收者之间的强联系。我们只需要将硬币传递个面前的人,直到给到售票员手里,算是这个任务结束。如果不使用职责链模式,我就得先搞清楚谁是售票员,才能把硬币递给他。
10.1 订单案例
公司针对支付过定金的用户有一定的优惠政策。
-
500元定金的用户: 会收到100元的商城优惠券,
-
200元定金的用户: 可以收到50元的优惠券,
-
普通用户: 无优惠券,且受到库存的影响
-
而之前没有支付定金的用户自动降级为普通购买模式,
-
orderType: 1: 500元定金用户, 2: 200元 , 3: 普通用户
-
isPay: 是否支付过 true: 是, false: 否
-
stock 库存量
10.2 实现需求
// 订单函数 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 优惠券复制代码
10.2 改进一下
上面的实现使用了太多的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 是紧紧耦合在一起的
10.3 使用职责链模式改进函数
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);;复制代码
改进之前:
使用职责链改进后: 这个请求或者任务 会在往下传递, 直到有人接手完成了它,否则会一直传递下去,这个类似于 上级给一层层下级传递任务。10.4 异步的职责链
// 异步职责链 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();复制代码
10.5 总结
-
使用了职责链模式之后,链中的节点对象可以灵活地拆分重组。增加或者删除一个节点,或者改变节点在链中的位置都是轻而易举的事情。这一点我们也已经看到,在上面的例子中, 增加一种订单完全不需要改动其他订单函数中的代码。
-
实际上只要运用得当,职责链模式可以很好地帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。职责链中的节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点。