Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

读《JavaScript设计模式与开发实践》学习 职责链 模式 #23

Open
lizhongzhen11 opened this issue Jun 30, 2019 · 0 comments
Labels
设计模式 设计模式

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Jun 30, 2019

啰嗦

  在家蹉跎一段时间,终于找到工作了,扬州真互联网荒漠,不过幸运的是居然在隔壁镇上找到java开发工作,虽然技术很老旧,我都不会的那种,好在同事之间互帮互助。就这样先在农村蛰伏,养好身体,当然,技术这里不能荒废,还是要学的。
  目前最大的问题就是学习效率极度低下。比如《es6入门》,前后看了不下5遍,常用的不看都能记住,不怎么用的比如generator还有async/await等较新的api总是忘记怎么玩,太菜了。不过每次看都有收获吧。
  《JavaScript设计模式与开发实践》这书也有整一个月没看了,今天拾起来继续攻读,收获颇丰,这个职责链模式真的让我这个代码质量极差的人耳目一新!

搬运工

  书上写的很棒了,我简要讲下,并搬运过来,主要警示我以后写业务代码的时候,多动点脑子,写出那种赏心悦目、维护性高的代码。
  职责链模式其实有点链式传递的意思,在js中,比如作用域链、原型链都有它的身影。简要概括就是:一个请求有多个对象来处理,这些对象是一条链,但具体由哪个对象来处理,根据条件判断来确定,如果不能处理会传递给该链中的下一个对象,直到有对象处理它为止。责任链模式将请求和处理分离开来,进行解耦。

考虑下面场景:电商平台做活动,比如付定金预购某商品得到优惠券,500元定金可以得到100优惠券,200元定金可以得到50元优惠券,优惠券直接当钱用,而不买优惠券就原价购买商品,原价购买商品受库存影响。这是个十足的业务需求,我很可能会写出类似书上的那种许多if...else的糟糕代码,然后被队友疯狂吐槽:

// orderType: 订单类型;1--花500买的优惠券;2--花200买的优惠券;3--原价购买
// stock:库存剩余数量,已买优惠券的不受此限制
if (orderType === 1) {
  console.log('付了500元定金,得到100优惠券')
}
if (orderType === 2) {
  console.log('付了200元定金,得到50优惠券')
}
if (orderType === 3 && stock > 0) {
  console.log('原价购买')
}

咋一看,好像3个if判断没问题,业务的确解决了,但是电商业务是经常变化的!我这里直接考虑的是用户下单付了定金的情况,如果像书上那样存在下单不付钱的情况呢?
我是不是要继续加判断?
如果优惠券是限量的,用户下单但没付款呢,我是不是还得加判断?
随着判断越来越多,这段代码将变得非常难看,甚至直接影响心情!
那我该怎么办?

利用职责链模式来重构代码!
第一版

var order500 = function(orderType, stock) {
  if (orderType === 1) {
    console.log('付了500元定金,得到100优惠券')
  } else {
    order200(orderType, stock)
  }
}

var order200 = function(orderType, stock) {
  if (orderType === 2) {
    console.log('付了200元定金,得到50优惠券')
  } else {
    orderNormal(orderType, stock)
  }
}

var orderNormal = function(orderType, stock) {
  if (stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('库存不足')
  }
}

第一版代码将每种情况封装成函数,根据业务区调用相应的函数即可,即使特定业务条件修改,也只需要修改函数内部判断,比之前一堆if连在一起好看得多。
不过,这种方法也存在缺陷,用书上的话讲,传递请求的代码被耦合在了业务函数中,违反了开放——封闭原则。如果以后增加300元预定或者去掉200元预定,也需要改动较多。那么这条职责链会变得非常不稳固!

如何改进?看看第二版:

var order500 = function(orderType, stock) {
  if (orderType === 1) {
    console.log('付了500元定金,得到100优惠券')
  } else {
    return 'nextSuccessor'
  }
}

var order200 = function(orderType, stock) {
  if (orderType === 2) {
    console.log('付了200元定金,得到50优惠券')
  } else {
    return 'nextSuccessor'
  }
}

var orderNormal = function(orderType, stock) {
  if (stock > 0) {
    console.log('普通购买,无优惠券')
  } else {
    console.log('库存不足')
  }
}

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

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

Chain.prototype.passRequest = function () {
  var ret = this.fn.apply(this, arguments);
  if (ret === 'nextSuccessor') {
    return this.successor && this.successor.passRequest.apply(this.successor, arguments)
  }
  return ret
}
// 分别包装成职责链节点
var chainOrder500 = new Chain(order500);
var chainOrder200 = new Chain(order200);
var chainOrderNormal = new Chain(orderNormal);
// 指定职责链顺序
chainOrder500.setNextSuccessor(chainOrder200);
chainOrder200.setNextSuccessor(chainOrderNormal);
// 传递请求
chainOrder500.passRequest(1, 500); // 付了500元定金,得到100优惠券
chainOrder500.passRequest(2, 500); // 付了200元定金,得到50优惠券
chainOrder500.passRequest(3, 500); // 普通购买,无优惠券
chainOrder500.passRequest(3, 0); // 库存不足

通过改进,我们可以自由灵活地增加、移除和修改链中的节点顺序,可维护性更高!

以上代码来自书中,我仅仅将其搬运过来,方便日常查找。

职责链模式也存在一定的弊端,首先不能保证请求一定会被链中节点处理,其次过长的职责链也会带来性能损耗。

回味

其实对于这个模式,我业务中还没有实践,所以只停留在理论上,不过它很适合已知参数但是未知参数值的if...else判断

@lizhongzhen11 lizhongzhen11 added the 设计模式 设计模式 label Jul 3, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
设计模式 设计模式
Projects
None yet
Development

No branches or pull requests

1 participant