在这里我们先想象一个场景,假设我们是一个售卖手机的网站,前期出过500到200的定金活动,现在已经进入正式购买阶段。已经支付过 500 元定金的用户会收到 100 元的商城优惠券,200 元定金的用户可以收到 50 元的优惠券,而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到。 我们可以从服务器拿到以下数据

  • orderType:表示订单类型(定金用户或者普通购买用户),code 的值为 1 的时候是 500 元定金用户,为 2 的时候是 200 元定金用户,为 3 的时候是普通购买用户。
  • pay:表示用户是否已经支付定金,值为 true 或者 false, 虽然用户已经下过 500 元定金的订单,但如果他一直没有支付定金,现在只能降级进入普通购买模式。
  • stock:表示当前用于普通购买的手机库存数量,已经支付过 500 元或者 200 元定金的用户不受此限制。

下面的代码是我们能轻而易举的写出的代码

var 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 优惠券
复制代码

这段代码可以得到我们想要的结果,但是这段代码的可维护性和可阅读性都很差,下面我们可以使用职责链模式来尝试改进它。

顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

问题解决: 职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

代码如下:

// 500 元订单
var order500 = function (orderType, pay, stock) {if (orderType === 1 && pay === true) {console.log('500 元定金预购, 得到 100 优惠券')} else {order200(orderType, pay, stock) // 将请求传递给 200 元订单}
}
// 200 元订单
var order200 = function (orderType, pay, stock) {if (orderType === 2 && pay === true) {console.log('200 元定金预购, 得到 50 优惠券')} else {orderNormal(orderType, pay, stock) // 将请求传递给普通订单}
}
// 普通购买订单
var orderNormal = function (orderType, pay, stock) {if (stock > 0) {console.log('普通购买, 无优惠券')} else {console.log('手机库存不足')}
}
// 测试结果:
order500(1, true, 500) // 输出:500 元定金预购, 得到 100 优惠券
order500(1, false, 500) // 输出:普通购买, 无优惠券
order500(2, true, 500) // 输出:200 元定金预购, 得到 500 优惠券
order500(3, false, 500) // 输出:普通购买, 无优惠券
order500(3, false, 0) // 输出:手机库存不足
复制代码

这个函数和前面的order函数执行结果完全一致,但是代码结构已经清晰了很多,我们避免了一些冗余的ifelse,并且将一个体积庞大的函数拆分成逻辑更加清晰的小函数。但是这样拆分明显也有一个问题,请求的传递是强耦合的,即500order和200的order是强耦合的,如果我们需要添加一个400元的订单,那么我又需要去修改函数内部,那么有没有更加灵活的方式呢?答案是有的。

我们可以用一个职责链类Chain和特定的传递请求的字符串'nextSuccessor'来拆分职责链节点

var order500 = function (orderType, pay, stock) {if (orderType === 1 && pay === true) {console.log('500 元定金预购,得到 100 优惠券')} else {return 'nextSuccessor' // 我不知道下一个节点是谁,反正把请求往后面传递}
}
var order200 = function (orderType, pay, stock) {if (orderType === 2 && pay === true) {console.log('200 元定金预购,得到 50 优惠券')} else {return 'nextSuccessor' // 我不知道下一个节点是谁,反正把请求往后面传递}
}
var orderNormal = function (orderType, pay, stock) {if (stock > 0) {console.log('普通购买,无优惠券')} else {console.log('手机库存不足')}
}
复制代码

接下来就是使用职责链类Chain

// Chain.prototype.setNextSuccessor 指定在链中的下一个节点
// Chain.prototype.passRequest 传递请求给某个节点
var Chain = function (fn) {this.fn = fnthis.successor = null
}
Chain.prototype.setNextSuccessor = function (successor) {return 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
}
复制代码

现在我们把 3 个订单函数分别包装成职责链的节点:

var chainOrder500 = new Chain(order500)
var chainOrder200 = new Chain(order200)
var 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(){// 具体实现略
};
chainOrder300= new Chain( order300 );
chainOrder500.setNextSuccessor( chainOrder300);
chainOrder300.setNextSuccessor( chainOrder200);
复制代码

使用职责链模式,我们可以只增加一个节点并且调整顺序即可就,并不会像第一个函数一样需要修改订单函数代码,因为在实际场景中,业务逻辑远远比这个复杂,出错率也比这个例子高得多。

异步的职责链

在上文中,我们使用同步返回的'nextSuccess'表示需要传递请求给下一个节点,但是实际开发中肯定会遇到异步场景,这时候我们需要手动的触发一个next方法

Chain.prototype.next= function(){return this.successor && this.successor.passRequest.apply( this.successor, arguments );
};
复制代码

如下例子

var fn1 = new Chain(function () {console.log(1)return 'nextSuccessor'
})
var fn2 = new Chain(function () {console.log(2)var self = thissetTimeout(function () {self.next()}, 1000)
})
var fn3 = new Chain(function () {console.log(3)
})
fn1.setNextSuccessor(fn2).setNextSuccessor(fn3)
fn1.passRequest()
复制代码

职责链模式优点

  1. 降低了请求发送者和请求接受者的耦合关系,我们不用关心它走了哪一个请求,我们都交给第一个节点处理就行
  2. 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
  3. 增加新的请求处理类很方便。

缺点

  1. 不能保证请求一定被接收, 除非我们在链尾处理了这种请求。
  2. 系统性能将受到一定影响,在请求过程中,大部分节点仅仅做了请求传递的作用,并且系统会增加额外的职责链类

使用职责链模式来重构你的代码相关推荐

  1. 图解Java设计模式学习笔记——行为型模式(模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式)

    一.模板方法模式(模板模式)--钩子方法 1.需求-豆浆制作问题 编写制作豆浆的程序,说明如下: 制作豆浆的流程选材-->添加配料-->浸泡-->放到豆浆机打碎. 通过添加不同的配料 ...

  2. 责任链模式(职责链模式)(Chain of Responsibility Pattern)

    学校OA 系统的采购审批项目:需求是 采购员采购教学器材 如果金额小于等于5000, 由教学主任审批(0<=x<=5000) 如果金额小于等于10000, 由院长审批(5000<x& ...

  3. 设计模式---职责链模式(Chain of Responsibility Pattern)

    目录 1.学校 OA系统采购审批需求 2.传统方式解决审批流程 3.传统 方式 问题分析 4.职责链模式基本介绍 5.职责链模式原理类图 6.职责链模式解决OA采购审批 7.职责链模式在SpringM ...

  4. 职责链模式应用——下机(机房重构知识点总结)

    下机涉及两个方面,消费时间和消费金额. 对消费时间的处理用的是职责链模式,感觉这个模式用的非常妙,參考的师哥的博客:<机房收费下机中用到的策略与职责链解析>:消费金额的处理用策略模式.针对 ...

  5. 设计模式之职责链模式、减小了因为分支带来的耦合

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

  6. C#设计模式之二十职责链模式(Chain of Responsibility Pattern)【行为型】

    一.引言 今天我们开始讲"行为型"设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中的例 ...

  7. C#设计模式学习笔记:(20)职责链模式

    本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/8109100.html,记录一下学习过程以备后续查用. 一.引言 今天我们要讲行为型设计模式的第八个模式--职 ...

  8. 王争 | 设计模式之美 - 职责链模式

    文章目录 1. 职责链模式的定义 2. 职责链模式的代码实现方式1 1. 处理器抽象类 Handler 2. 具体处理器 HandlerA 和 HandlerB 3. 处理器链 HandlerChai ...

  9. 模板方法模式和职责链模式

    一.模板方法模式 1.模板方法模式,基于继承的设计模式,由两部分组成,抽象父类和具体实现子类. 2.例子Coffe 和 Tea //创建抽象类 -- 饮料function Beverage(){}Be ...

最新文章

  1. LeetCode实战:最接近的三数之和
  2. SVN详解-linux+windows
  3. 工信部:2017工业物联网白皮书
  4. python画-一步一步教你如何用Python画一个滑稽
  5. tensorflow2.0支持的python版本-TensorFlow 版本兼容性
  6. 斯坦福大学深度学习与自然语言处理第四讲:词窗口分类和神经网络
  7. C语言查看文件fp指针位置
  8. 我的第一个 react redux demo
  9. gc:C语言的垃圾回收库-英文
  10. android6变化,一次尝鲜体验 关于一加6升级Android P后的变化
  11. BZOJ5343[Ctsc2018]混合果汁——主席树+二分答案
  12. concat oracle 多个字符串_12个常用的JavaScript字符串方法
  13. pythonsocket中tcp通信接收不到数据_简单说说Python Socket编程步骤?
  14. solidity教程(二)僵尸攻击人类
  15. iOS播放器SDK-基于FFmpeg解码OpenGL渲染-CYPlayer
  16. h5页面怎么处理文件流_微信H5页面制作流程,大家有哪些经验分享?
  17. 写个爬虫爬取p站画师的画作
  18. html怎么吧图片设置成背景音乐,如何把照片做成视频并添加音乐
  19. 小程序自定义导航栏指南
  20. linux命令的含义,Linux常见命令及含义

热门文章

  1. 有道精品课python-有道精品课-Python小咖养成计划
  2. python基础常用语句-Python基础语法
  3. python 单词发音-在python中的单词上拆分语音音频文件
  4. yolov5 v3.0训练出现KeyError错误
  5. DL-4 深度学习中的batch_size、epoch、iteration的区别
  6. Floyd cycle算法
  7. UVa11134 Fabled Rooks(贪心算法)
  8. LeetCode Remove Duplicates from Sorted List II
  9. 一致性hash算法简介
  10. LeetCode Spiral Matrix II (生成螺旋矩阵)