JavaScript设计模式-职责链模式

职责链模式

职责链模式指的是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

概念

节点:一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象,我们把这些对象称为链中的节点

职责链的结构

职责链由一个个节点构成,每个节点都是一个对象,对象中都包含相同的属性名和方法名,这样就容易添加、删除节点。

构造函数,用来构造链中的节点,每个节点都保存处理函数,记录下一个节点。

function Chain (fn){
  this.fn = fn;
  this.successor = null; 
}

设置当前节点的下一个处理的节点,与其他节点建立链接,从而形成链式结构

Chain.prototype.setSuccessor = function (successor){
  this.successor = successor;
}

执行处理函数,根据处理结果判断是否需要继续执行。

// 传递请求给某个节点。统一规定当函数返回nextSuccessor时将请求传递给下一个函数
Chain.prototype.passRequest = function (){
  let ret = this.fn.apply(this, arguments);
  if(ret === 'nextSuccessor'){
    this.successor && this.successor.passRequest.apply(this.successor, arguments);
  }
  return ret;
}

示例:订购手机

如果用户预付定金500元,则获得100元优惠。如果用户预付定金200元,则获得50元优惠。如果不预付定金,当库存不足的时候得不到手机,当库存足够的时候可以得到手机。

// 预付定金500的处理函数
function order500(orderType, pay, stock){
  if(orderType === 1 && pay){
    console.log('500元定金已付,获得100元优惠券');
  } else {
    return 'nextSuccessor';
  }
}

// 预付定金200的处理函数
function order200(orderType, pay, stock){
  if(orderType === 2 && pay){
    console.log('200元定金已付,获得50元优惠券');
  } else {
    return 'nextSuccessor';
  }
}

// 不预付定金的处理函数
function orderNormal(orderType, pay, stock){
  if(stock > 0){
    console.log('普通购买,暂无优惠券');
  } else {
    console.log('手机库存不足');
  }
}

// 构造函数,用来构造链中的节点
function Chain (fn){
  this.fn = fn; // 当前处理的节点
  this.successor = null; // 下一个处理的节点
}

// 设置下一个处理的节点
Chain.prototype.setSuccessor = function (successor){
  this.successor = successor;
}


// 传递请求给某个节点。统一规定当函数返回nextSuccessor时将请求传递给下一个函数
Chain.prototype.passRequest = function (){
  let ret = this.fn.apply(this, arguments);
  if(ret === 'nextSuccessor'){
    this.successor && this.successor.passRequest.apply(this.successor, arguments);
  }
  return ret;
}

let chain500 = new Chain(order500);
let chain200 = new Chain(order200);
let chainNormal = new Chain(orderNormal);
chain500.setSuccessor(chain200);
chain200.setSuccessor(chainNormal);

chain500.passRequest(1, true, 500);
chain500.passRequest(2, true, 500);
chain500.passRequest(0, true, 1);

示例:异步职责链

// 构造函数,用来构造链中的节点
function Chain(fn) {
    this.fn = fn;
    this.successor = null;
  }


// 设置下一个节点
  Chain.prototype.setSuccessor = function (successor) {
    this.successor = successor;
  }
// 处理请求
  Chain.prototype.passRequest = function () {
    let ret = this.fn.apply(this, arguments);
  }
  
// 传递请求到下一个节点
  Chain.prototype.next = function () {
    this.successor && this.successor.fn.apply(this.successor, arguments);
  }

  function payment() {
    setTimeout(() => {
      console.log('第一阶段完成');
      this.next();
    }, 2000);
  }

  function unionPay() {
    setTimeout(() => {
      console.log('第二阶段完成');
      this.next();
    }, 2000);
  }

  function request() {
    setTimeout(() => {
      console.log('第三阶段完成');
    }, 2000);
  }

  let chainPayment = new Chain(payment);
  let chainUnionPay = new Chain(unionPay);
  let chainRequest = new Chain(request);

  chainPayment.setSuccessor(chainUnionPay);
  chainUnionPay.setSuccessor(chainRequest);
  chainPayment.passRequest();

职责链模式的优缺点

优点

  • 解耦了请求者和多个接收者之间的复杂关系,只需要把请求发给第一个节点即可,不必关心被谁处理
  • 可以灵活地添加链中的节点和设置节点的顺序
  • 可以手动指定起始节点,节点并不是一定从第一个节点开始

缺点

  • 不能保证某个的请求一定会被链中的节点处理
  • 当链较长时会造成性能损耗

职责链模式的应用场景

职责链模式适用于对同一请求多重处理的情况,例如:对于请求处理,不同的状态使用不同的处理逻辑,只需要交给第一个处理对象,然后就会自动传递处理。

总结

职责链模式可以很好地帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。职责链中的节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点
无论是作用域链、原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链模式的影子

你可能感兴趣的:(JavaScript设计模式,javascript,设计模式,前端)