关于责任链模式我所知道的

简介: 关于责任链模式我所知道的

image.png


本文已参与「新人创作礼」活动,一起开启掘金创作之路。

关键词:Command ChainOfResponsibility

责任链模式在我们平时开发过程中随处可见,比如作用域链、原型链、事件冒泡等。

什么是原型链 __proto__



image.png



为什么这么设计?

JS 为了实现面向对象编程的一种设计,基于原型链可以让 JS 对象拥有封装继承多态等面向对象的特性。

什么是事件冒泡?



image.png



事件冒泡:交互事件发生后,从最小元素 div 开始传播,传到顶层 document

为什么这么设计?

最小元素上可能没有绑定 onclick 事件,所以得层层传递,传到绑定了事件函数的元素上。

换句话说:事件源本身(可能)没有处理事件的能力。


解决什么问题


上述两个例子简单介绍了下职责链模式的经典用例,类比到日常其实就像我们上学的时候上课传纸条、玩击鼓传花,纸条 谁是赵日天?,从第一排传下去,如果不是就不会应答,继续往后传递。

先来看两段珍贵无比的代码,走进职责链模式的内心世界:


业务逻辑集合递减


需求:


  1. 已生成订单,定金 500,商城优惠券 100元
  2. 已生成订单,定金 200,商城优惠券 50 元
  3. 正常购买,是否有库存,原价购买
  4. 下了单没付钱的一律按照原价购买

改造前:

/**
 * orderType: 1 -> 500定金 2 -> 200定金 3 -> 普通购买
 * isPaid -> 是否已支付定金
 * stock -> 库存
 */
function getOrder(orderType, isPaid, stock) {
  // 500元定金购买模式
  if (orderType === 1) {
    // 已支付定金       
    if (isPaid === true) {
      console.log('500元定金预购,得到100优惠券');
    } else { // 未支付定金,降级到普通购买模式   
      // 用于普通购买的手机还有库存
      if (stock > 0) {
        console.log('普通购买,无优惠券');
      } else {
        console.log('库存不足');
      }
    }
    return
  }
  // 200元定金购买模式
  if (orderType === 2) {
    if (pay === true) {
      console.log('200元定金预购, 得到50优惠券');
    } else {
      if (stock > 0) {
        console.log('普通购买, 无优惠券');
      } else {
        console.log('库存不足');
      }
    }
    return
  }
  if (orderType === 3) {
    if (stock > 0) {
      console.log('普通购买, 无优惠券');
    } else {
      console.log('库存不足');
    }
  }
}
getOrder(1, true, 500); // 500元定金预购,得到100优惠券


问题:代码冗余,大量重复的业务逻辑,难以维护。用职责链模式对代码进行改造。

改造后:

// 定义职责链上的各个节点
const orderFor500 = (orderType, isPaid, stock) => {
  if (orderType === 1 && isPaid) {
    console.log('500元定金预购 得到100优惠券')
  } else {
    return 'nextTick'
  }
}
const orderFor200 = (orderType, isPaid, stock) => {
  if (orderType === 2 && isPaid) {
    console.log('200元定金预购 得到500优惠券')
  } else {
    return 'nextTick'
  }
}
const orderForNormal = (orderType, isPaid, stock) => {
  if (stock > 0) {
    console.log('普通购买, 无优惠券')
  } else {
    console.log('库存不足')
  }
}
// 定义职责链
class Chain {
  constructor(fn) {
    this.fn = fn
    this.nextTick = null
  }
  setNextTick(nextTick) {
    return this.nextTick = nextTick
  }
  permit() {
    const res = this.fn.apply(this, arguments);
    if (res === 'nextTick') {
      return this.nextTick && this.nextTick.permit.apply(this.nextTick, arguments)
    }
    return res
  }
}


测试代码:

// 声明节点
const chainOrder500 = new Chain(orderFor500);
const chainOrder200 = new Chain(orderFor200);
const chainOrderNormal = new Chain(orderForNormal);
// 指定顺序
chainOrder500.setNextTick(chainOrder200)
chainOrder200.setNextTick(chainOrderNormal)
// 测试
chainOrder500.permit(1, true, 500)
chainOrder500.permit(2, true, 500)
chainOrder500.permit(3, true, 500)
chainOrder500.permit(1, false, 0)
// 500元定金预购 得到100优惠券
// 200元定金预购 得到500优惠券
// 普通购买, 无优惠券
// 库存不足

这样的写法也便于以后拓展,比如运营同学说:350 - 75

const orderFor350 = (orderType, isPaid, stock) => {
  // code   
}
const chainOrder350 = new Chain(orderFor350);
chainOrder500.setNextTick(chainOrder350)
chainOrder350.setNextTick(chainOrder200)


改造职责链使其能够异步


在节点函数中发起异步请求,异步请求返回的结果决定是否继续在职责链中 permit

这时候让节点函数同步返回 nextTick 就没有意义了,所以 Chain 类需要增加方法 $next,手动传递请求给职责链中的下一个节点。

// 定义职责链
class Chain {
  constructor(fn) {
    this.fn = fn
    this.nextTick = null
  }
  $next() {
    return this.nextTick && this.nextTick.permit.apply(this.nextTick, arguments);
  }
  setNextTick(nextTick) {
    return this.nextTick = nextTick
  }
  permit() {
    const res = this.fn.apply(this, arguments);
    if (res === 'nextTick') {
      return this.nextTick && this.nextTick.permit.apply(this.nextTick, arguments)
    }
    return res
  }
}
// 定义节点
const node1 = new Chain(function () {
  showResult('node-1')
  return 'nextTick'
})
const node2 = new Chain(function () {
  showResult('node-2')
  const _this = this;
  const timer = setTimeout(() => {
    _this.$next()
    clearTimeout(timer)
  }, 1000)
})
const node3 = new Chain(function () {
  showResult('node-3')
})
// 测试代码
node1.setNextTick(node2).setNextTick(node3)
node1.permit()


image.png


请求在链中的节点里传递,节点则确定什么时候把请求交给下一个节点。


定义


在 GoF 给出的定义: 在职责链模式中,多个处理器依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。

应用场景


主要应用于解耦发起请求的对象和处理请求的对象,更好的帮助我们管理代码。针对不同场景处理请求。就比如优惠券,发帖的审核等。

参考资料:

refactoringguru 责任链模式

目录
相关文章
|
1月前
|
设计模式 JavaScript 前端开发
如何优雅的使用责任链模式?
【6月更文挑战第7天】如何优雅的使用责任链模式?
|
2月前
|
设计模式
职责链模式
职责链模式
21 0
|
10月前
|
设计模式 Java
设计模式~~~责任链模式(职责链模式)
设计模式~~~责任链模式(职责链模式)
45 0
|
设计模式 数据安全/隐私保护
玩转责任链模式
责任链模式原理介绍
201 0
|
设计模式 Java
Java设计模式-责任链模式(ChainOfResponsibility)
Java设计模式-责任链模式(ChainOfResponsibility)
|
设计模式 数据处理
我学会了,职责链模式
职责链模式属于行为型模式,这个类型的设计模式总结出了 类、对象之间的经典交互方式,将类、对象的行为和使用解耦了,花式的去使用对象的行为来完成特定场景下的功能。
97 0
我学会了,职责链模式
责任链模式简单介绍
责任链模式简单介绍
117 0
|
设计模式 JavaScript Java
|
Java Nacos Sentinel
责任链模式详解(上)
责任链模式详解
211 0
责任链模式详解(上)
|
设计模式 XML 数据格式