目录
介绍
职责链的定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象(这些对象称为链的”节点”)连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
订单实例
假如我们接收了这么一个需求: 前后端合作实现一个售卖手机的电商网站,后台下发以下字段值:
- orderType: 表示订单类型。取值1表示500元定金用户,取值2表示200元定金用户,取值3表示普通购买用户;
- pay: 表示用户是否已经支付定金。取值 true 或 false;
- stock: 普通购买的手机库存数量,已支付500元和200元的用户不受限制。
代码实现:
// 500元订单var order500 = funcrion(orderType, pay, stock) {if (orderType === 1 && pay === true) {console.log('500元定金预购,得到100优惠券');} else {order200(orderType, pay, stock); // 将请求传递给200元订单}};// 200元订单var order200 = function(orderType, pay, stock) {if (orderType === 2 && pay === true) {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); // 输出: 500元定金预购,得到100优惠券order500(1, false, 500); // 输出: 普通购买,无优惠券order500(2, true, 500); // 输出: 200元定金预购,得到50元优惠券order500(3, false, 500); // 输出: 普通购买,无优惠券order500(3, false, 0); // 输出: 手机库存不足
以上代码简单运用了职责链模式,然而代码仍有不足,这段代码违反了开放-封闭原则,如果我们要修改某些业务逻辑,那么肯定要动到函数内部代码,这显然不合理,所以我们必须进一步优化代码。
实现灵活可拆分的职责节点
如果要把之前的职责链模式实例代码进一步优化,我们可以从实现灵活拆分和重组的链节点这个目标出发。
最终实现的代码如下:
// 500元订单var order500 = funcrion(orderType, pay, stock) {if (orderType === 1 && pay === true) {console.log('500元定金预购,得到100优惠券');} else {return 'nextSuccessor'; // 无需知道传递给什么节点,只需向后传递请求即可}};// 200元订单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 {console.log('手机库存不足');}}// Chain构造函数接收一个需要包装的函数作为参数var Chain = function(fn) {this.fn = fn;this.successor = null;};// setNextSuccessor函数用于指定在链中的下一个节点Chain.prototype.setNextSuccessor = function(successor) {return this.successor = successor;};// passRequest函数用于传递请求给某个节点Chain.prototype.passRequest = function() {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.setNextSuccessor(chainOrder200);chainOrder200.setNextSuccessor(chainOrderNormal);// 把请求传递给第一个节点chainOrder500.passRequest(1, true, 500);chainOrder500.passRequest(2, true, 500);chainOrder500.passRequest(3, true, 500);chainOrder500.passRequest(1, false, 0);
如此一来,我们就只是增加一个节点,然后重新设置链中相关节点的顺序。
异步职责链
在现实开发中,我们经常会遇到一些异步的问题,比如我们要在节点函数中发起一个 ajax 异步请求,异步请求返回的结果才能决定是否继续在职责链中 passRequest。这时候让节点函数同步返回”nextSuccessor”已经没有意义了,所以要给 Chain 类再增加一个原型方法 Chain.prototype.next,表示手动传递请求给职责链中的下一个节点。
实现的代码如下:
// ... 内容省略// 手动传递节点的函数Chain.prototype.next = function() {return this.successor && this.successor.passRequest.apply(this.successor, arguments);};var fn1 = new Chain(function() {console.log(1);return 'nextSuccessor';});var fn2 = new Chain(function() {console.log(2);var self = this;setTimeout(function() {self.next();}, 1000);});var fn3 = new Chain(function() {console.log(3);});fn1.setNextSuccessor(fn2).setNextSuccessor(fn3);fn1.passRequest();
职责链模式的优缺点
优点
职责链模式最大的优点就是解耦了请求发送者和N个接收者之间的复杂关系,由于不知道链中的哪个节点可以处理你发出的请求,所以你只需把请求传递给第一个节点即可。
职责链模式的另一个优点就是,可以手动指定起始节点,请求并不是非得从链中的第一个节点开始传递。
缺点
职责链模式也存在着一些缺点,首先,我们不能保证某个请求一定会被链中的节点处理。另外,职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分节点并没有起到实质性的作用,它们的作用仅仅是让请求传递下去,从性能方面考虑,我们要避免过长的职责链带来的性能损耗。
ID : 58DATE : 2018/01/07AUTHER : WJT20TAG : JavaScript
