前端杂记让前端飞前端开发笔记

职责链模式

2018-12-29  本文已影响0人  会飞小超人

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

有这样一个需求:

假设我们负责一个售卖手机的电商网站,经过分别交纳500元定金和200元定金的两轮预定后(订单已在此时生成),现在已经到了正式购买的阶段。
公司针对支付过定金的用户有一定的优惠政策。在正式购买后,已经支付过500元定金的用户会收到100元的商城优惠券,200元定金的用户可以收到50元的优惠券,而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到。

这个需求写成代码就是这样:

const order = function (orderType, pay, stock) {
  if (orderType === 1) {        // 500元定金购买模式
    if (pay === true) {    // 已支付定金
      console.log('500元定金预购, 得到100优惠券');
    } else {    // 未支付定金,降级到普通购买模式
      if (stock > 0) {    // 用于普通购买的手机还有库存
        console.log('普通购买, 无优惠券');
      } else {
        console.log('手机库存不足');
      }
    }
  } else if (orderType === 2) {     // 200元定金购买模式
    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('手机库存不足');
    }
  }
};

order(1, true, 500);  // 输出: 500元定金预购, 得到100优惠券

这样的代码有下面的这些问题:

使用职责链模式重写

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('手机库存不足')
  }
}

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

Chain.prototype.setNextSuccessor = function (successor) {
  return this.successor = successor
}

Chain.prototype.passRequest = function () {
  let ret = this.fn.apply(this, arguments)

  if (ret === 'nextSuccessor') {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments)
  }

  return ret
}

const chainOrder500 = new Chain(order500)
const chainOrder200 = new Chain(order200)
const chainOrderNormal = new Chain(orderNormal)

chainOrder500.setNextSuccessor(chainOrder200)
chainOrder200.setNextSuccessor(chainOrderNormal)

chainOrder500.passRequest( 1, true, 500 );    // 输出:500元定金预购,得到100优惠券
chainOrder500.passRequest( 2, true, 500 );    // 输出:200元定金预购,得到50优惠券
chainOrder500.passRequest( 3, true, 500 );    // 输出:普通购买,无优惠券
chainOrder500.passRequest( 1, false, 0 );     // 输出:手机库存不足

这样子,就把各个阶段的逻辑解耦开了,如果需要增加300元的优惠策略,也比较容易:

var order300 = function(){
  // 300价位订单的处理逻辑
};

chainOrder300= new Chain( order300 );
chainOrder500.setNextSuccessor( chainOrder300);
chainOrder300.setNextSuccessor( chainOrder200);

利用js的高级函数,还能更加简洁方便的创建职责链:

/* 用AOP实现职责链模式 */
Function.prototype.after=function(fn){
  let self=this
  return function(){
    let ret=self.apply(this,arguments)
    if(ret==='nextSuccessor'){
      return fn.apply(this,arguments)
    }

    return ret
  }
}

let order=order500.after(order200).after(orderNormal)

order( 1, true, 500 );    // 输出:500元定金预购,得到100优惠券
order( 2, true, 500 );    // 输出:200元定金预购,得到50优惠券
order( 1, false, 500 );   // 输出:普通购买,无优惠券

用AOP来实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能有较大的影响。

我的理解:职责链模式算是迭代器模式的一个延伸,里面的思想与迭代器模式有些相似之处。迭代器是把队列每个元素作为输入,然后用户自己定义处理逻辑,而职责链是用户指定多个处理逻辑,处理同一个输入,只有满足条件的那个处理逻辑才能真正输出,而其他处理逻辑只是把输入传递给下一个处理逻辑。

上一篇 下一篇

猜你喜欢

热点阅读