定义

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
**职责连是由多个不同的对象组成的,发送者是发送请求的对象,接收者接收请求并且对其进行处理或传递的对象。基本流程如下:

  1. 发送者知道链中的第一个接收者,它向这个接收者发送该请求。
  2. 每一个接收者都对请求进行分析,然后要么处理它,要么它往下传递。
  3. 每一个接收者知道其他的对象只有一个,即它在链中的下家(successor)。
  4. 如果没有任何接收者处理请求,那么请求会从链中离开。

职责链模式是个链式结构,请求在链中的节点之间依次传递,直到有一个对象能处理该请求为止。如果没有任何对象处理该请求的话,那么请求就会从链中离开。

demo

参考链接
这个例子并不好但是可以帮助我们理解职责链这种设计模式

以电商网站抽奖为例,规则如下:

  1. 用户充值>=500元,可以100%中奖100元红包
  2. 用户充值>=200元,可以100%中奖20元红包
  3. 用户不充值,也可以抽奖,但概率极低。
  4. 用户充值失败,按不充值处理。

注意的是
用户充值之后的如果大于500是100&中奖的,而大于200时是100%中20,当然也应该先有可能中20的,所以一般的流程就规定了先从500往下判断,当然可以先判断是否充值成功;

参数讲解

  1. /**
  2. * 用户抽奖
  3. * @param orderType 1:500 2:2000
  4. * @param isPay 充值是否成功
  5. * @param count 充值金额
  6. */

面向过程

  1. var order = function(orderType,isPay,count) {
  2. if(isPay === true){ //如果充值成功的话
  3. if(orderType === 1) // 用户充值500元 100%中奖
  4. console.log("亲爱的用户,您中奖了100元红包了");
  5. else if(orderType === 2)// 用户充值200元 100%中奖
  6. console.log("亲爱的用户,您中奖了20元红包了");
  7. }else {
  8. if(count > 0) {
  9. console.log("亲爱的用户,您已抽到10元优惠卷");
  10. }else {
  11. console.log("亲爱的用户,请再接再厉哦");
  12. }
  13. }
  14. };

职责链实现

定义三种方法(结果)

  1. function order500(orderType,isPay,count){
  2. if(orderType === 1 && isPay === true) {
  3. console.log("亲爱的用户,您中奖了100元红包了");
  4. }else {
  5. //我不知道下一个节点是谁,反正把请求往后面传递
  6. return "nextSuccessor";
  7. }
  8. }
  9. function order200(orderType,isPay,count) {
  10. if(orderType === 2 && isPay === true) {
  11. console.log("亲爱的用户,您中奖了20元红包了");
  12. }else {
  13. //我不知道下一个节点是谁,反正把请求往后面传递
  14. return "nextSuccessor";
  15. }
  16. }
  17. function orderNormal(orderType,isPay,count){
  18. // 普通用户来处理中奖信息
  19. if(count > 0) {
  20. console.log("亲爱的用户,您已抽到10元优惠卷");
  21. }else {
  22. console.log("亲爱的用户,请再接再厉哦");
  23. }
  24. }

职责链

  1. class Chain{
  2. constructor(fn){
  3. this.fn = fn;
  4. this.successor = null;
  5. }
  6. // 设置下一个节点
  7. setNextSuccessor(successor){
  8. return this.successor = successor;
  9. };
  10. // 把请求往下传递
  11. passRequest(){
  12. let ret = this.fn.apply(this,arguments);
  13. // 需要进行下一节点
  14. if(ret === 'nextSuccessor') {
  15. return this.successor && this.successor.passRequest.apply(this.successor,arguments);
  16. }
  17. return ret;
  18. }
  19. }

调用

  1. //现在我们把3个函数分别包装成职责链节点:
  2. var chainOrder500 = new Chain(order500);
  3. var chainOrder200 = new Chain(order200);
  4. var chainOrderNormal = new Chain(orderNormal);
  5. // 然后指定节点在职责链中的顺序
  6. chainOrder500.setNextSuccessor(chainOrder200);
  7. chainOrder200.setNextSuccessor(chainOrderNormal);
  8. //最后把请求传递给第一个节点:
  9. chainOrder500.passRequest(1,true,500); // 亲爱的用户,您中奖了100元红包了
  10. chainOrder500.passRequest(2,true,500); // 亲爱的用户,您中奖了20元红包了
  11. chainOrder500.passRequest(3,true,500); // 亲爱的用户,您已抽到10元优惠卷
  12. chainOrder500.passRequest(1,false,0); // 亲爱的用户,请再接再厉哦

异步

promise其实是职责链模式的一种很好的封装实现

总结

优点

  1. 解耦了请求发送者和度个接收者之间的复杂关系,不需要知道链中哪个节点能处理你的请求,只需要把请求传递到第一个节点即可。
  2. 链中的节点对象可以灵活地拆分重组,增加或删除一个节点,或者改变节点的位置都是很简单的事情。
  3. 我们还可以手动指定节点的起始位置,并不是说非得要从其实节点开始传递的.

    缺点

    职责链模式中多了一点节点对象,可能在某一次请求过程中,大部分节点没有起到实质性作用,他们的作用只是让请求传递下去,从性能方面考虑,避免过长的职责链提高性能。