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

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

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

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

无论是作用域链,原型链,还是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. PHP mkdir 方法 创建 0777 权限的目录问题

    php 中使用 mkdir() 方法创建 0777 权限的目录: $path = './Logs/secondCheck/';if(!is_dir($path)){ mkdir($path, 0777 ...

  2. ThinkPHP 学习笔记 ( 二 ) 控制器 ( Controller )

    /** * ThinkPHP version 3.1.3 * 部署方式:应用部署 * 文内的 http://localhost/ 由实际主机地址代替 */ 入口文件 index.php: <?p ...

  3. Django 1.8安装使用

    1.使用pip安装django, pip是什么,如何安装?自行放狗搜 # pip install "django<1.9" 2.创建项目 # django-admin sta ...

  4. Swing 刷新容器

    JPanel pchks = new JPanel();// 容器刷新(重新layout所有空间)pchks.validate();// 容器重绘(当容器内的东西由多变少时,防止多出来的部分没有清楚) ...

  5. MuPlayer『百度音乐播放内核』

    MuPlayer『百度音乐播放内核』 —— 跨平台.轻量级的音频播放解决方案. 多端(PC & WebApp)通用,统一的API调用方式 HTML5 Audio与Flash内核的平滑切换(支持 ...

  6. ExtJS笔记5 Components

    参考 :http://blog.csdn.net/zhangxin09/article/details/6914882 An Ext JS application's UI is made up of ...

  7. Web前端开发:什么是页面重回(repaints)与回流(reflow)

    前言:什么是重绘与回流? 重绘(repaints)是一个元素外观的改变所触发的浏览器行为,例如改变vidibility.outline.背景色等属性.浏览器会根据元素的新属性重新绘制,使元素呈现新的外 ...

  8. 页面静态化3 --- (伪静态+ob缓存)实现优化

    要求:使用伪静态完成简单的新闻查询! 伪静态是站在SEO的角度来看的,他对应的页面不是真正存在的(而真静态的页面是事先生成的),而是每次查询数据库得到的信息!

  9. laravel paginate动态分页

    1.router Route::get('product', function(){ $products = App\Product::paginate(10); return view('produ ...

  10. 在MyEclipse下创建Java Web项目 入门(图文并茂)经典教程

    http://jijiaa12345.iteye.com/blog/1739754 在MyEclipse下创建Java Web项目 入门(图文并茂)经典教程 本文是一篇在Myeclipse下构建Jav ...