一、职责链的定义和使用场景

职责链模式的定义是,职责链模式将一系列可能会处理请求的对象连接成一条链,请求在这些对象之间一次传递,直到遇到一个可以处理它的对象。从而避免请求的发送者和接收者之间的耦合关系。

职责链模式的优点是:请求发送者只需要直到链中的第一个节点,从而解耦了发送者和一组接收者之间的强联系。此外,使用了职责链模式之后,链中的节点对象可以灵活地拆分重组,增加或者删除 一个节点,以及改变节点在链中的位置都是轻而易举的。

职责链模式的缺点是:首先不能保证某个请求一定会被链中的某个节点处理,这种情况系下可以在链尾增加一个保底的接受者节点来处理这种即将离开链尾的请求。其次,职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分的节点并没有起到实质性的作用,从性能的角度考虑,应当避免过长的职责链带来的性能损耗。

无论是作用域链,原型链,还是DOM节点中的事件冒泡,从中都可以找到职责链模式的影子。

结合自己开发经验,在轻量级MVVM的实现中,就体现了职责链的设计模式。

1.具有指向下一个节点的属性:this.parent

2.在具体的事件处理函数中进行递归调用,以便事件沿着职责链的方向传递(冒泡?)

二、职责链模式应用案例

假设有这么一种场景:一个售卖手机的电商网站,经过分别交纳500元定金和200元定金的两轮预订之后(订单在此时已经生成),现在进入了正式购买阶段。

公司针对支付过定金的客户有一定的优惠,正式购买之后,已经支付过500元定金的用户会收到100元优惠券,200元定金的用户可以收到50元优惠券,没有支付过定金的只能进入普通购买方式,也就是没有优惠券。相关的字段有这么几种:

oederType:订单类型,为1代表500元定金用户,2代表200元定金用户,3为普通购买用户;

    //职责链模式学习
var order500=function(orderType,pay,stock){
if(orderType==&&pay===true){
console.log('500元定金预约,得到100元优惠券');
}else{
return 'nextSuccessor';
}
};
var order200=function(orderType,pay,stock){
if(orderType===&&pay===true){
console.log('200元定金预约,得到50优惠券');
}else{
return 'nextSuccessor';
}
}; var orderNormal=function(orderType,pay,stock){
if(stock>){
console.log('普通购买,无优惠券');
}else{
return 'nextSuccessor';
}
};

接下来需要把函数包装进职责链节点:

//职责链包装

    var Chain=function(fn){
this.fn=fn;
this.nextSuccessor=null;
}; Chain.prototype.setNextSuccessor=function(successor){
return this.nextSuccessor=successor;
}; Chain.prototype.passRequest=function(){
var ret=this.fn.apply(this,arguments); if(ret=='nextSuccessor'){
//console.log(this.nextSuccessor.fn.name);
return this.nextSuccessor&&this.nextSuccessor.passRequest.apply(this.nextSuccessor,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(,true,);//输出 500元定金,得到100元优惠券
chainOrder500.passRequest(,true,);//输出200元定金,得到50元优惠券
chainOrder500.passRequest(,false,); //输出 手机库存不足

三、异步的职责链

在之前的职责链中,我们让每个节点都返回一个特定值nextSuccessor,来表示将请求传递给下一个节点,在现实生活中,经常会遇到一些异步的问题,比如发送ajax请求,由ajax请求的结果来决定是否传递给下一个节点,此时同步返回nextSuccessor已经没有意义了,需要给Chain类增加Chain.prototype.next,用于手动传递请求给下一个节点。

    Chain.prototype.next=function(){
return this.nextSuccessor&&this.nextSuccessor.passRequest.apply(this.nextSuccessor,arguments);
};

四、使用AOP的方式实现职责链

之前的案例采用Chain将普通函数包装成职责链的节点,实际上有一种更加方便的方式来创建职责链。

    //使用AOP的方式创建职责链
Function.prototype.after=function(afterFn){
var self=this;
return function(){
var ret=self.apply(this,arguments);
if(ret==='nextSuccessor'){
ret=afterFn.apply(this.arguments);
}
return ret;
}; }; var order=order500.after(order200).after(orderNormal);
order(,false,);

javascript设计模式学习之十三——职责链模式的更多相关文章

  1. atitit.设计模式(1)--—职责链模式(chain of responsibility)最佳实践O7 日期转换

    atitit.设计模式(1)---职责链模式(chain of responsibility)最佳实践O7 日期转换 1. 需求:::日期转换 1 2. 可以选择的模式: 表格模式,责任链模式 1 3 ...

  2. 重温设计模式(三)——职责链模式(chain of responsibility)

    一. 写在前面的 这么多的设计模式,我觉得职责链是我第一次看上去最简单,可是回想起来却又最复杂的一个模式. 因此,这个文章我酝酿了很久,一直也没有胆量发出来,例子也是改了又改,可是仍然觉得不够合理.所 ...

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

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

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

    一.引言 今天我们开始讲“行为型”设计模式的第八个模式,该模式是[职责链模式],英文名称是:Chain of Responsibility Pattern.让我们看看现实生活中的例子吧,理解起来可能更 ...

  5. js设计模式(12)---职责链模式

    0.前言 老实讲,看设计模式真得很痛苦,一则阅读过的代码太少:二则从来或者从没意识到使用过这些东西.所以我采用了看书(<js设计模式>)和阅读博客(大叔.alloyteam.聂微东)相结合 ...

  6. 设计模式 --> (15)职责链模式

    职责链模式 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 示例 考虑员工要求加薪.公司的管理者一共有 ...

  7. JS设计模式(10)职责链模式(重要)

    什么是职责链模式? 重要性:4 星,在项目中能对 if-else 语句进行优化 定义:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到 ...

  8. javascript设计模式学习之十六——状态模式

    一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...

  9. JavaScript设计模式学习——builder pattern(建造者模式)

    个人理解的应用场景 举个例子,比如想要创建各种类型的车的实例,车的类型有很多种,但创建每种类型车的接口定义可能是一样的,就用到了此模式 相关概念的通俗解释 上述例子中接口的定义叫builder 接口到 ...

随机推荐

  1. centos最小安装,之后想安装x-windows,安装图形界面 startx

    yum groupinstall "Desktop"yum groupinstall "X Window System"安装完成之后,reboot一下,不然硬件 ...

  2. [ZZ] KlayGE 游戏引擎 之 Order Independent Transparency(OIT)

    转载请注明出处为KlayGE游戏引擎,本文的永久链接为http://www.klayge.org/?p=2233 http://dogasshole.iteye.com/blog/1429665 ht ...

  3. 提高Vector容器的删除效率

    vector容器是类似与一个线性数组,索引效率高,插入,删除的效率很低,需要遍历数据列表,一般情况下vector的删除操作由一下函数完成: iterator erase(iterator positi ...

  4. Fingerprinting

    https://wiki.mozilla.org/Fingerprinting Fingerprinting   Contents 1 Overview 2 Data 2.1 Plugins 2.2 ...

  5. redis配置文件中文解释

    # redis 配置文件示例 # 当你需要为某个配置项指定内存大小的时候,必须要带上单位, # 通常的格式就是 1k 5gb 4m 等酱紫: # # 1k => bytes # 1kb => ...

  6. Http请求工具

    package cn.com.test; import java.io.BufferedReader; import java.io.IOException; import java.io.Input ...

  7. hive中的常用方法(case,cast,unix_timestamp)

    1.case的用法 )格式1 case col when value then '' when value then '' else '' end )格式2 case when col='value' ...

  8. Scala Tail Recursion (尾递归)

    Scala对尾递归进行了优化,甚至提供了专门的标注告诉编译器需要进行尾递归优化.不过这种优化仅限于严格的尾递归,间接递归等情况,不会被优化. 尾递归的概念 递归,大家都不陌生,一个函数直接或间接的调用 ...

  9. php中的编码问题

    转自:http://www.jb51.net/article/22501.htm php的header来定义一个php页面为utf编码或GBK编码 php页面为utf编码 header("C ...

  10. C# RichTextBox 滚动条 滚动到最后一行

    使用RichTextBox控件用于显示数据时,滚动条只停留在开头,而我希望能够一直更新,显示最后一行的内容.解决方法记录于此. 转载自以下链接: http://blog.csdn.net/xelone ...