深入理解JavaScript系列(38):设计模式之职责链模式详解


Posted in Javascript onMarch 04, 2015

介绍

职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。

也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确知道哪一个对象将会处理它——也就是该请求有一个隐式的接受者(implicit receiver)。根据运行时刻,任一候选者都可以响应相应的请求,候选者的数目是任意的,你可以在运行时刻决定哪些候选者参与到链中。

正文

对于JavaScript实现,我们可以利用其原型特性来实现职责链模式。

var NO_TOPIC = -1;

var Topic;
function Handler(s, t) {

    this.successor = s || null;

    this.topic = t || 0;

}
Handler.prototype = {

    handle: function () {

        if (this.successor) {

            this.successor.handle()

        }

    },

    has: function () {

        return this.topic != NO_TOPIC;

    }

};

Handler只是接受2个参数,第一个是继任者(用于将处理请求传下去),第二个是传递层级(可以用于控制在某个层级下是否执行某个操作,也可以不用),Handler原型暴露了一个handle方法,这是实现该模式的重点,先来看看如何使用上述代码。
var app = new Handler({

        handle: function () {

            console.log('app handle');

        }

    }, 3);
    var dialog = new Handler(app, 1);
    var button = new Handler(dialog, 2);
    button.handle();

改代码通过原型特性,调用代码从button.handle()->dialog.handle()->app.handle()->参数里的handle(),前三个都是调用原型的handle,最后才查找到传入的参数里的handle,然后输出结果,也就是说其实只有最后一层才处理。

那如何做到调用的时候,只让dialog的这个对象进行处理呢?其实可以定义dialog实例对象的handle方法就可以了,但需要在new button的之前来做,代码如下:

var app = new Handler({

        handle: function () {

            console.log('app handle');

        }

    }, 3);
    var dialog = new Handler(app, 1);

    dialog.handle = function () {

        console.log('dialog before ...')

        // 这里做具体的处理操作

        console.log('dialog after ...')

    };
    var button = new Handler(dialog, 2);
    button.handle();

该代码的执行结果即时dialog.handle里的处理结果,而不再是给app传入的参数里定义的handle的执行操作。

那能不能做到自身处理完以后,然后在让继任者继续处理呢?答案是肯定的,但是在调用的handle以后,需要利用原型的特性调用如下代码:

Handler.prototype.handle.call(this);

该句话的意思说,调用原型的handle方法,来继续调用其继任者(也就是successor )的handle方法,以下代码表现为:button/dialog/app三个对象定义的handle都会执行。
var app = new Handler({

    handle: function () {

        console.log('app handle');

    }

}, 3);
var dialog = new Handler(app, 1);

dialog.handle = function () {

    console.log('dialog before ...')

    // 这里做具体的处理操作

    Handler.prototype.handle.call(this); //继续往上走

    console.log('dialog after ...')

};
var button = new Handler(dialog, 2);

button.handle = function () {

    console.log('button before ...')

    // 这里做具体的处理操作

    Handler.prototype.handle.call(this);

    console.log('button after ...')

};
button.handle();

通过代码的运行结果我们可以看出,如果想先自身处理,然后再调用继任者处理的话,就在末尾执行Handler.prototype.handle.call(this);代码,如果想先处理继任者的代码,就在开头执行Handler.prototype.handle.call(this);代码。

总结

职责链模式经常和组合模式一起使用,这样一个构件的父构件可以作为其继任者。

同时,DOM里的事件冒泡机制也和此好像有点类似,比如点击一个按钮以后,如果不阻止冒泡,其click事件将一直向父元素冒泡,利用这个机制也可以处理很多相关的问题,比如本系列设计模式享元模式里的《例1:事件集中管理》的示例代码。

Javascript 相关文章推荐
基于jQuery的固定表格头部的代码(IE6,7,8测试通过)
May 18 Javascript
innerText和textContent对比及使用介绍
Feb 27 Javascript
Google Map V3 绑定气泡窗口(infowindow)Dom事件实现代码
Apr 26 Javascript
javascript回车完美实现tab切换功能
Mar 13 Javascript
jquery-tips悬浮提示插件分享
Jul 31 Javascript
简单的jQuery banner图片轮播实例代码
Mar 04 Javascript
JS实现页面数据无限加载
Sep 13 Javascript
jQuery插件MovingBoxes实现左右滑动中间放大图片效果
Feb 28 Javascript
js实现全选反选不选功能代码详解
Apr 24 Javascript
layui select 禁止点击的实现方法
Sep 05 Javascript
微信小程序自定义tabBar的踩坑实践记录
Nov 06 Javascript
一篇超完整的Vue新手入门指导教程
Nov 18 Vue.js
教你如何使用firebug调试功能了解javascript闭包和this
Mar 04 #Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
Mar 04 #Javascript
jQuery插件开发的五种形态小结
Mar 04 #Javascript
深入理解JavaScript系列(36):设计模式之中介者模式详解
Mar 04 #Javascript
百度UEditor编辑器如何关闭抓取远程图片功能
Mar 03 #Javascript
jQuery实现复选框成对选择及对应取消的方法
Mar 03 #Javascript
js实现文本框中输入文字页面中div层同步获取文本框内容的方法
Mar 03 #Javascript
You might like
windows的文件系统机制引发的PHP路径爆破问题分析
2014/07/28 PHP
php轻量级的性能分析工具xhprof的安装使用
2015/08/12 PHP
非常实用的php验证码类
2016/05/15 PHP
深入解析PHP中SESSION反序列化机制
2017/03/01 PHP
你需要知道的JavsScript可以做什么?
2007/06/29 Javascript
表格 隔行换色升级版
2009/11/07 Javascript
jquery validate使用攻略 第四步
2010/07/01 Javascript
推荐40个非常优秀的jQuery插件和教程【系列三】
2011/11/09 Javascript
js点击更换背景颜色或图片的实例代码
2013/06/25 Javascript
Redis基本知识、安装、部署、配置笔记
2015/03/05 Javascript
jquery中JSON的解析方式
2015/03/16 Javascript
jQuery实现的小图列表,大图展示效果幻灯片示例
2016/10/25 Javascript
Vue.js鼠标悬浮更换图片功能
2017/05/17 Javascript
JS实现上传图片的三种方法并实现预览图片功能
2017/07/14 Javascript
JS实现table表格固定表头且表头随横向滚动而滚动
2017/10/26 Javascript
JavaScript指定断点操作实例教程
2018/09/18 Javascript
JavaScript实现的级联算法示例【省市二级联动功能】
2018/12/25 Javascript
详解基于iview-ui的导航栏路径(面包屑)配置
2019/02/22 Javascript
微信小程序 this.triggerEvent()的具体使用
2019/12/10 Javascript
jQuery实现的移动端图片缩放功能组件示例
2020/05/01 jQuery
Python基于Tkinter的HelloWorld入门实例
2015/06/17 Python
Python3内置模块pprint让打印比print更美观详解
2019/06/02 Python
Linux下通过python获取本机ip方法示例
2019/09/06 Python
python+gdal+遥感图像拼接(mosaic)的实例
2020/03/10 Python
Python使用graphviz画流程图过程解析
2020/03/31 Python
HTML5 canvas画图并保存成图片的jcanvas插件
2014/01/17 HTML / CSS
Marlies Dekkers内衣美国官方网上商店:高端内衣品牌
2018/11/12 全球购物
在印度上传处方,在线订购药品:Medlife
2019/03/28 全球购物
中学老师的自我评价
2013/11/07 职场文书
考博专家推荐信模板
2013/12/02 职场文书
整改通知书格式
2015/04/22 职场文书
检讨书格式范文
2015/05/07 职场文书
2015年网管个人工作总结
2015/05/22 职场文书
教师见习总结范文
2015/06/23 职场文书
Dashboard管理Kubernetes集群与API访问配置
2022/04/01 Servers
js前端面试常见浏览器缓存强缓存及协商缓存实例
2022/06/21 Javascript