博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
传递请求之职责链模式
阅读量:6894 次
发布时间:2019-06-27

本文共 5497 字,大约阅读时间需要 18 分钟。

职责链模式其实很好理解,由于一个链字出卖了它的灵魂。我们可以从这个字得到很大的提示。首先这个模式一定有传递性,而且,节点是可以重复拼接的,并且每个节点都具有一定的过滤功能,一定的职责。

是不是想起了组合模式里的一些内容呢? 是的,他们两个有着天然的类似点,不过组合模式主要职责是给执行者添加一些列行为,而不区分内部的执行。职责链模式则会强调内部的细节,他可以手动传递权限,手动终止权限。

举个栗子吧:

小时候,俺是一个学渣,平时作业都不会做,但是老师硬性要求你做。没办法,只有去借鉴学霸的作业。首先,我们班人都超级好,我做在最后一排,然后

我问前一排的妹纸: 嗨,小芳,你的作业能给我看看嘛?小芳: 我作业没做呢?我帮你问问前面的。小芳: 小明,你作业做完了吗?能给我看看嘛?小明: 我作业没做呢?我帮你问问前面的。小明: 小吉,你作业做完了吗?能给我看看嘛?小吉: 做完了,给你吧。

恩,good,事情圆满解决。完美的体现出,职责链的内涵,上一节点,只要知道下一个节点的接口,so that enough。 如果本身节点能够完成任务,则将结果输出,终止传递。

用代码标识即为:

function Me (flag){    if(flag===1){        console.log("I can do this homeword");    }else{        console.log("I can't :(, but u can do this ?");        XiaoFang(flag);    }}function XiaoFang (flag){    if(flag===1){        console.log("I can do this homeword");    }else{        console.log("I can't :(, but u can do this ?");        XiaoJi(flag);    }}function XiaoJi (flag){    if(flag===0){        console.log("I can do this homeword");    }else{        console.log("I can't :(, but u can do this ?");            //...继续询问下一个人    }}Me(0);

没错,职责链的主要内涵就是,如果你不行,在问问下一个人行不行。。。但是上面代码让我有种想kill people的冲动(不是写的烂,是写的太烂了),唯一能够表扬他的就是,知道职责链模式的原理。所以为了情怀,我们需要给上面的代码换一身皮.

function Chain(fn){    this.fn = fn;    this.nextExer = null;}Chain.prototype.setNext = function(obj){    this.nextExer = obj;}Chain.prototype.exe = function(flag){    var result = this.fn.apply(this,arguments);    if(result === "next"){        this.next(flag);    }}Chain.prototype.next = function(){    return this.nextExer.exe.apply(this.nextExer,arguments)}var fn1 = new Chain(function(flag){    if(flag===1){        console.log("I can do this homework");    }else{        console.log("I can't do this homework");        return "next";    }});var fn2 = new Chain(function(flag){    if(flag===1){        console.log("I can do this homework");    }else{        console.log("I can't do this homework");        return "next";    }})var fn3 = new Chain(function(flag){    if(flag===0){        console.log("I can do this homework");    }else{        console.log("I can't do this homework");        return "next";    }})fn1.setNext(fn2);fn2.setNext(fn3);fn1.exe(0);

虽然,上面这段代码看起来清晰很多,使用next调用下一个函数,使用exe初始化.但是看起来在setNext哪里有点啰嗦。我们试着改进:

Chain.prototype.setNext = function(obj){    this.nextExer = obj;    return obj;}fn1.setNext(fn2).setNext(fn3);fn1.exe(0);

只需要将setNext哪里返回一个Obj,就可以得到完美的链式调用了。可以从上面的代码中看出一些端倪,在职责链模式中,我们需要规定,在每个exe执行过后需要设置一个result,并且这个result必须能明确的标识下一个到底继不继续。

当然,要知道,这个职责链模式并不是一定要把管理权交给内部执行,你当然也可以在外面进行判断和设置。

var fn2 = new Chain(function(flag){    console.log("I can't do this homework");    this.nextExer.fn(0);  //手动执行下一个})

通过上面的步骤,可以在外部直接判断,是否执行下一个。所以职责模式的写法也是很多的。

职责链的利弊

而且,职责链最大的一个好处就是,你可以从链中,任意一个节点开始遍历。 我们用上面那个例子体会一下。

假如,我前面座的童鞋,我和他都同时喜欢一女生,所以我俩关系超差。我当然不能问情敌要作业啦,这时候,我可以再往前一个同学问。利用职责模式就为.

xiaoMing.setNext(xiaoFang).setNext(xiaoJi);//改写,直接从小芳开始xiaoFang.setNext(xiaoJi);

这应该算是职责链模式的一大特色,但是这个也不是没有问题的,就是我们需要在最后一个节点上加上判断,表示如果没有其他处理程序,而且在该节点上也不成立的话,则需要抛出一个错误,或者做出相应的说明. 并且,我们每次请求的时候,都会从节点链的开始进行遍历,这样很可能会造成性能的损失,所以这里需要注意的是,不要设置太长的职责链。

使用AOP

这里AOP指的是面向切面编程,即将其他函数动态的加入到一个函数中,比如before & after. 我们仔细想想,一个队列无外乎就是在前在后的关系,所以一个before和after已经算是万能的了(排除你有动态删除的需求)。

Function.prototype.after = function(fn){    var _this = this;    return function(){        var res = _this.apply(this,arguments);        if(!res){  //值为Boolean            return fn.apply(this,arguments);        }        return res;    }}Function.prototype.before = function(fn){    var _this = this;    return function(){        fn.apply(this,arguments);        return    _this.apply(this,arguments);    }}

上面已经将AOP中两个最重要的before和after添加到Function的原型里面了。

现在我们可以使用这两把三相之力开启职责链模式

XiaoMing.after(XiaoFang).after(XiaoJi);

我操,完美啊,通俗易懂哎喂。

如果我们需要加上判断的话,可以直接在after和before里面写

//只举before的例子吧Function.prototype.before = function(fn){    var _this = this;    return function(){        var res = fn.apply(this,arguments);  //值为Boolean,表示是否继续向下传递        if(res===false){  //如果返回不成立,则继续向下传递            return    _this.apply(this,arguments);        }    }}function Xiaoming(){    console.log("I can do this homework");    return "ok"; //中断返回,当然这里你可以随便定义,除了"next"}function XiaoFang(){    console.log("I can't do this homework");    return "next";}Xiaoming. before(XiaoFang)();

职责链模式之干货

我们这里再次回忆一下职责链模式的用处,将一个请求依照一条链传递,如果有个满足则断开传递,返回结果。 想一想,这个和我们的迭代器模式有着异曲同工的妙处,迭代器模式同样也是遍历选出最优解,但是相比而言,职责链模式的直观性个书写的幸福感是远远超过迭代器模式的。

在写一些hacks的时候,难免会用到if...else if...判断语句,上次我们使用迭代器模式完成这样的功能,但是效果不是很理想,这里我们使用职责链模式完成。

事件模式的选择函数

Function.prototype.after = function(fn){    var _this = this;    return function(){        var res = _this.apply(this,arguments);        if(res==="next"){  //值为Boolean            return fn.apply(this,arguments);        }        return res;    }}var bind = (function() {    var DOM2 = function() {        if (document.addEventListener) {            return function(ele, fn, type) {                ele.addEventListener(type, () => {                    fn();                }, false);            }        } else {            return "next";        }    };    var IE = function() {        if (document.attachEvent) {            return function(ele, fn, type) {                ele.attachEvent(type, fn);            }        } else {            return "next";        }    };    var DOM0 = function(){        return function(ele, fn, type) {            ele[`on${type}`] = () => {                fn();            };        }    }    return DOM2.after(IE).after(DOM0)();})();console.log(bind);

恩,以上结果只是一个简单地示范。 这里需要提个醒,职责链模式是设计模式中最容易忘记的模式之一,因为它好用到不叫模式。所以,职责链模式的用法也是很多的,希望大家多多探索,将自己学到的只是分享出来,这是,极好的呀!

转载地址:http://oskdl.baihongyu.com/

你可能感兴趣的文章
可以给redis的hash中的hashKey设置expire吗?
查看>>
Python获取本机 IP/MAC(多网卡)
查看>>
jQuery EasyUI 学习资料链接整理
查看>>
iOS textView 选中指向左上角
查看>>
OpenSSL学习(十二):基础-指令gendsa
查看>>
vscode 如何创建自定义代码片段
查看>>
mac:python:pycharm:osx:可怕的case-sensitive硬盘格式
查看>>
绑定程序集
查看>>
Java Programming Review (1)
查看>>
chrome离线安装包
查看>>
MySQL备份与恢复
查看>>
Unsupported major.minor version
查看>>
PHP框架高级编程——应用Symfony、CakePHP和Zend
查看>>
读取xml节点值生成一个实体类,读取xml所有节点值,读取所有xml所有节点名称
查看>>
优秀的Java程序员必须了解GC的工作原理
查看>>
nodejs踩坑日记,持续更新
查看>>
项目部署时一些常见linux命令和遇到的问题
查看>>
RAC 归档目录不同的备份
查看>>
Ubuntu中root用户和user用户的相互切换
查看>>
入门知识点
查看>>