深入理解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 相关文章推荐
ExtJS TabPanel beforeremove beforeclose使用说明
Mar 31 Javascript
js二维数组排序的简单示例代码
Jan 24 Javascript
介绍一个简单的JavaScript类框架
Jun 24 Javascript
JavaScript中的原型prototype完全解析
May 10 Javascript
javascript稀疏数组(sparse array)和密集数组用法分析
Dec 28 Javascript
微信小程序实战之运维小项目
Jan 17 Javascript
在vue-cli脚手架中配置一个vue-router前端路由
Jul 03 Javascript
用vue构建多页面应用的示例代码
Sep 20 Javascript
JS数组去重常用方法实例小结【4种方法】
May 28 Javascript
vue.js将时间戳转化为日期格式的实现代码
Jun 05 Javascript
微信小程序文章列表功能完整实例
Jun 03 Javascript
解决js中的setInterval清空定时器不管用问题
Nov 17 Javascript
教你如何使用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
解析Win7 XAMPP apache无法启动的问题
2013/06/26 PHP
php/js获取客户端mac地址的实现代码
2013/07/08 PHP
PHP中使用数组指针函数操作数组示例
2014/11/19 PHP
php对二维数组进行相关操作(排序、转换、去空白等)
2015/11/04 PHP
PHP创建/删除/复制文件夹、文件
2016/05/03 PHP
Yii2.0表关联查询实例分析
2016/07/18 PHP
iis6手工创建网站后无法运行php脚本的解决方法
2017/06/08 PHP
JQuery下关于$.Ready()的分析
2009/12/13 Javascript
浅析jQuery中常用的元素查找方法总结
2013/07/04 Javascript
JS动态创建Table,Tr,Td并赋值的具体实现
2013/07/05 Javascript
javascript中CheckBox全选终极方案
2015/05/20 Javascript
JS去除空格和换行的正则表达式(推荐)
2016/06/14 Javascript
bootstrap日历插件datetimepicker使用方法
2016/12/14 Javascript
jQuery分页插件jquery.pagination.js使用方法解析
2017/02/09 Javascript
基于AngularJS实现表单验证功能
2017/07/28 Javascript
使用JavaScript实现一个小程序之99乘法表
2017/09/21 Javascript
mui框架移动开发初体验详解
2017/10/11 Javascript
浅谈vuex 闲置状态重置方案
2018/01/04 Javascript
vue 实现左右拖拽元素并且不超过他的父元素的宽度
2018/11/30 Javascript
Vue项目环境搭建详细总结
2019/09/26 Javascript
Node绑定全局TraceID的实现方法
2019/11/14 Javascript
JS精确判断数据类型代码实例
2019/12/18 Javascript
JS实现容器模块左右拖动效果
2020/01/14 Javascript
Nodejs文件上传、监听上传进度的代码
2020/03/27 NodeJs
[01:58]最残酷竞争 2016国际邀请赛中国区预选赛积分循环赛回顾
2016/06/28 DOTA
Python计算一个文件里字数的方法
2015/06/15 Python
详解Python的Django框架中Manager方法的使用
2015/07/21 Python
Python-opencv 双线性插值实例
2020/01/17 Python
Python 动态变量名定义与调用方法
2020/02/09 Python
Python要如何实现列表排序的几种方法
2020/02/21 Python
Python lxml库的简单介绍及基本使用讲解
2020/12/22 Python
css3实现背景模糊的三种方式(小结)
2020/05/15 HTML / CSS
运动会广播稿400字
2014/01/25 职场文书
考试后的感想
2015/08/07 职场文书
创业计划书之孕婴生活馆
2019/11/11 职场文书
python使用opencv对图像添加噪声(高斯/椒盐/泊松/斑点)
2022/04/06 Python