js设计模式-职责链模式

445 阅读3分钟
定义

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

举个例子

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

  • orderType:表示订单类型(定金用户或者普通购买用户), code的值为1的时候是500元定金用户,为2的时候是200元定金用户,为3的时候是普通购买用户
  • pay:表示用户是否已经支付定金,值为true或者false,虽然用户已经下过500元定金的订单,但如果他一直没有支付定金,现在只能降级进入普通购买模式。
  • stock:表示当前用于普通购买的手机库存数量,已经支付过500元或者200元定金的用户不受此限制。
上代码
const order500 = (orderType:number, pay: boolean, stock: number) => {
  if (orderType === 1 && pay) {
    console.log('500定金预购,得到100优惠券')
  } else {
    return false
  }
}
const order200 = (orderType:number, pay: boolean, stock: number) => {
  if (orderType === 2 && pay) {
    console.log('200定金预购,得到50优惠券')
  } else {
    return false
  }
}
const orderNormal = (orderType:number, pay: boolean, stock: number) => {
  if (stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('内存不足')
  }
}

class Chain {
  public fn: Function
  public successor: any
  constructor(fn: Function) {
    this.fn = fn
    this.successor = null;
  }

  setNextSuccessor(successor: any) {
    return this.successor = successor
  }

  passRequest(orderType:number, pay: boolean, stock: number) {
    const ret = this.fn.apply(this,arguments);
    if (ret === false) {
      return this.successor && this.successor.passRequest.apply(this.successor, arguments)
    }
    return ret
  }

  next() {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments)
  }
}

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) // 内存不足

// 新增300order异步
const chainOrder300 = new Chain(function(orderType:number, pay: boolean, stock: number){
  setTimeout(() => {
    if (orderType === 4 && pay) {
      console.log('300定金预购,得到80优惠券')
    } else { // 如果是异步请求,同步返回false已经没有意义,所以此处需要手动next传递请求给下一个节点
      this.next()
    }
  }, 2000)
})

chainOrder500.setNextSuccessor(chainOrder300)
chainOrder300.setNextSuccessor(chainOrder200)

chainOrder500.passRequest(4, true, 300) // 300定金预购,得到80优惠券
优缺点
  • 从上述例子可以看出,在普通模式中由于不知道哪个节点可以处理发出的请求,所以我们的请求发送这和N个接收者之间都需要建立联系,而职责链模式中,在建立好请求之间的位置关系后,我们只需把请求传递给第一个节点就可。
  • 同时,链中的节点对象可以灵活地拆分重组,并且在你明确条件的情况下也可以直接传递给职责链中的任意一个节点。
  • 另外,职责链模式使得程序中多了一些节点对象,可能在某次请求中,大部分节点并没有起到实质性的作用,所以从性能方面考虑,我们要避免过长的职责链带来的性能损耗