职责链模式
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
实例
当我们使用京东或者淘宝买东西时,有些商品可能会根据是否付过定金以及定金的额度进行不同的处理,比如支付500定金的会赠送100元优惠券,200元赠送50优惠券等。转换成代码是这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| function userIdentity(orderType, pay, stock) { if (orderType === 1) { 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('手机库存不足'); } } }
userIdentity(1, true, 500);
|
这样写的坏处是嵌套了很多的if else语句,此外如果想要加入新的逻辑(比如新增300元的优惠券)会很麻烦。我们可以借助职责链模式来帮助我们简化代码:
- 首先将500,200,正常购买三个逻辑各自封装成函数,约定如果当前函数无法处理就返回
nextSuccessor 。
- 新建一个构造函数,用**
passRequset接收参数处理逻辑,setNextSuccessor**指定当前函数无法处理时的下一个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| const order500 = function (orderType, pay, stock) { if (orderType === 1 && pay === true) { console.log('500 元定金预购,得到 100 优惠券'); } else { return 'nextSuccessor'; } }; const order200 = function (orderType, pay, stock) { if (orderType === 2 && pay === true) { console.log('200 元定金预购,得到 50 优惠券'); } else { return 'nextSuccessor'; } }; const orderNormal = function (orderType, pay, stock) { if (stock > 0) { console.log('普通购买,无优惠券'); } else { console.log('手机库存不足'); } };
class Chain { constructor(fn) { this.fn = fn this.successor = null } setNextSuccessor(successor) { return this.successor = successor } passRequest() { const ret = this.fn.apply(this, arguments); if (ret === 'nextSuccessor') { return this.successor && this.successor.passRequest.apply(this.successor, arguments); } return ret; } next() { return this.successor && this.successor.passRequest.apply(this, arguments) } }
const chain500 = new Chain(order500) const chain200 = new Chain(order200) const chainNormal = new Chain(orderNormal) chain500.setNextSuccessor(chain200).setNextSuccessor(chainNormal)
chain500.passRequest(3,false,0)
|
如果不是同步的情况,例如当我们用职责链来处理异步逻辑,就不能直接在业务函数中直接返回**nextSuccessor而需要调用 next**进行下一步。
AOP实现职责链
但是AOP实现主要捋清楚各个this指向的关系,这点很重要。
1 2 3 4 5 6 7 8 9 10 11 12
| Function.prototype.after = function (fn) { const _this = this return function () { const res = _this.apply(this, arguments) if (res === 'nextSuccessor') { return fn.apply(this, arguments) } return res } } const order = order500.after(order200).after(orderNormal) order(1, true, 500);
|
总结
职责链模式可以很好地帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。
职责链中的节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点。无论是作用域链、原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链模式的影子。职责链模式还可以和组合模式结合在一起,用来连接部件和父部件,或是提高组合对象的效率。