Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
182 lines (150 sloc) 5.11 KB

职责链模式

职责链模式:类似多米诺骨牌,通过请求第一个条件,会持续执行后续的条件,直到返回结果为止。

重要性:4 星,在项目中能对 if-else 语句进行优化

场景 demo

场景:某电商针对已付过定金的用户有优惠政策,在正式购买后,已经支付过 500 元定金的用户会收到 100 元的优惠券,200 元定金的用户可以收到 50 元优惠券,没有支付过定金的用户只能正常购买。

// orderType: 表示订单类型,1:500 元定金用户;2:200 元定金用户;3:普通购买用户
// pay:表示用户是否已经支付定金,true: 已支付;false:未支付
// stock: 表示当前用于普通购买的手机库存数量,已支付过定金的用户不受此限制

const order = function( orderType, pay, stock ) {
  if ( orderType === 1 ) {
    if ( pay === true ) {
      console.log('500 元定金预购,得到 100 元优惠券')
    } else {
      if (stock > 0) {
        console.log('普通购买,无优惠券')
      } else {
        console.log('库存不够,无法购买')
      }
    }
  } else if ( orderType === 2 ) {
    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( 3, true, 500 ) // 普通购买,无优惠券

下面用职责链模式改造代码:

const order500 = function(orderType, pay, stock) {
  if ( orderType === 1 && pay === true ) {
    console.log('500 元定金预购,得到 100 元优惠券')
  } else {
    order200(orderType, pay, stock)
  }
}

const order200 = function(orderType, pay, stock) {
  if ( orderType === 2 && pay === true ) {
    console.log('200 元定金预购,得到 50 元优惠券')
  } else {
    orderCommon(orderType, pay, stock)
  }
}

const orderCommon = function(orderType, pay, stock) {
  if (orderType === 3 && stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('库存不够,无法购买')
  }
}

order500( 3, true, 500 ) // 普通购买,无优惠券

改造后可以发现代码相对清晰了,但是链路代码和业务代码依然耦合在一起,进一步优化:

// 业务代码
const order500 = function(orderType, pay, stock) {
  if ( orderType === 1 && pay === true ) {
    console.log('500 元定金预购,得到 100 元优惠券')
  } else {
    return 'nextSuccess'
  }
}

const order200 = function(orderType, pay, stock) {
  if ( orderType === 2 && pay === true ) {
    console.log('200 元定金预购,得到 50 元优惠券')
  } else {
    return 'nextSuccess'
  }
}

const orderCommon = function(orderType, pay, stock) {
  if (orderType === 3 && stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('库存不够,无法购买')
  }
}

// 链路代码
const chain = function(fn) {
  this.fn = fn
  this.sucessor = null
}

chain.prototype.setNext = function(sucessor) {
  this.sucessor = sucessor
}

chain.prototype.init = function() {
  const result = this.fn.apply(this, arguments)
  if (result === 'nextSuccess') {
    this.sucessor.init.apply(this.sucessor, arguments)
  }
}

const order500New = new chain(order500)
const order200New = new chain(order200)
const orderCommonNew = new chain(orderCommon)

order500New.setNext(order200New)
order200New.setNext(orderCommonNew)

order500New.init( 3, true, 500 ) // 普通购买,无优惠券

重构后,链路代码和业务代码彻底地分离。假如未来需要新增 order300,那只需新增与其相关的函数而不必改动原有业务代码。

另外结合 AOP 还能简化上述链路代码:

// 业务代码
const order500 = function(orderType, pay, stock) {
  if ( orderType === 1 && pay === true ) {
    console.log('500 元定金预购,得到 100 元优惠券')
  } else {
    return 'nextSuccess'
  }
}

const order200 = function(orderType, pay, stock) {
  if ( orderType === 2 && pay === true ) {
    console.log('200 元定金预购,得到 50 元优惠券')
  } else {
    return 'nextSuccess'
  }
}

const orderCommon = function(orderType, pay, stock) {
  if (orderType === 3 && stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('库存不够,无法购买')
  }
}

// 链路代码
Function.prototype.after = function(fn) {
  const self = this
  return function() {
    const result = self.apply(self, arguments)
    if (result === 'nextSuccess') {
      return fn.apply(self, arguments) // 这里 return 别忘记了~
    }
  }
}

const order = order500.after(order200).after(orderCommon)

order( 3, true, 500 ) // 普通购买,无优惠券

职责链模式比较重要,项目中能用到它的地方会有很多,用上它能解耦 1 个请求对象和 n 个目标对象的关系。