深入理解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 入门讲解1
Apr 15 Javascript
判断客户端浏览器是否安装了Flash插件的多种方法
Aug 11 Javascript
JavaScript 一道字符串分解的题目
Aug 03 Javascript
基于dropdown.js实现的两款美观大气的二级导航菜单
Sep 02 Javascript
jquery获取url参数及url加参数的方法
Oct 26 Javascript
flag和jq on 的绑定多个对象和方法(必看)
Feb 27 Javascript
微信小程序本地缓存数据增删改查实例详解
May 24 Javascript
JS简单判断是否在微信浏览器打开的方法示例
Jan 08 Javascript
用vscode开发vue应用的方法步骤
May 06 Javascript
一文读懂vue动态属性数据绑定(v-bind指令)
Jul 20 Javascript
封装 axios+promise通用请求函数操作
Aug 11 Javascript
Vue h函数的使用详解
Feb 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
Linux Apache PHP Oracle 安装配置(具体操作步骤)
2013/06/17 PHP
中高级PHP程序员应该掌握哪些技术?
2016/09/23 PHP
PHP抓取远程图片(含不带后缀的)教程详解
2016/10/21 PHP
php使用 readfile() 函数设置文件大小大小的方法
2017/08/11 PHP
PHP实现使用DOM将XML数据存入数组的方法示例
2017/09/27 PHP
HTML中Select不用Disabled实现ReadOnly的效果
2008/04/07 Javascript
40个有创意的jQuery图片、内容滑动及弹出插件收藏集之一
2011/12/31 Javascript
JavaScript中用toString()方法返回时间为字符串
2015/06/12 Javascript
jQuery实现的淡入淡出二级菜单效果代码
2015/09/15 Javascript
基于JavaScript实现一定时间后去执行一个函数
2015/12/14 Javascript
Bootstrap简单表单显示学习笔记
2016/11/15 Javascript
Angular实现的进度条功能示例
2018/02/18 Javascript
浅谈webpack 构建性能优化策略小结
2018/06/13 Javascript
小程序的上传文件接口的注意要点解析
2019/09/17 Javascript
JS猜数字游戏实例讲解
2020/06/30 Javascript
js异步接口并发数量控制的方法示例
2020/11/22 Javascript
调试Python程序代码的几种方法总结
2015/04/28 Python
Python语言的面相对象编程方式初步学习
2016/03/12 Python
浅谈Django中的数据库模型类-models.py(一对一的关系)
2018/05/30 Python
Pandas读取MySQL数据到DataFrame的方法
2018/07/25 Python
python 删除字符串中连续多个空格并保留一个的方法
2018/12/22 Python
PyCharm设置每行最大长度限制的方法
2019/01/16 Python
python制作填词游戏步骤详解
2019/05/05 Python
Django框架视图介绍与使用详解
2019/07/18 Python
python 字典的打印实现
2019/09/26 Python
django 取消csrf限制的实例
2020/03/13 Python
完美解决python针对hdfs上传和下载的问题
2020/06/05 Python
html5简单示例_动力节点Java学院整理
2017/07/07 HTML / CSS
html5 横向滑动导航栏的方法示例
2020/05/08 HTML / CSS
编程实现当输入某产品代码则打印出该产品记录的功能
2014/05/03 面试题
怎么样写好简历中的自我评价
2013/10/25 职场文书
大学自主招生自荐信
2013/12/16 职场文书
班级口号大全
2014/06/09 职场文书
研修心得体会
2014/09/04 职场文书
机器人总动员观后感
2015/06/09 职场文书
酒店厨房管理制度
2015/08/06 职场文书