职责链模式其实很好理解,因为一个链字出卖了它的灵魂。咱们能够从这个字获得很大的提示。首先这个模式必定有传递性,并且,节点是能够重复拼接的,而且每一个节点都具备必定的过滤功能,必定的职责。编程
是否是想起了组合模式里的一些内容呢? 是的,他们两个有着自然的相似点,不过组合模式主要职责是给执行者添加一些列行为,而不区份内部的执行。职责链模式则会强调内部的细节,他能够手动传递权限,手动终止权限。设计模式
举个栗子吧:app
小时候,俺是一个学渣,平时做业都不会作,可是老师硬性要求你作。没办法,只有去借鉴学霸的做业。首先,咱们班人都超级好,我作在最后一排,而后函数
我问前一排的妹纸: 嗨,小芳,你的做业能给我看看嘛? 小芳: 我做业没作呢?我帮你问问前面的。 小芳: 小明,你做业作完了吗?能给我看看嘛? 小明: 我做业没作呢?我帮你问问前面的。 小明: 小吉,你做业作完了吗?能给我看看嘛? 小吉: 作完了,给你吧。
恩,good,事情圆满解决。完美的体现出,职责链的内涵,上一节点,只要知道下一个节点的接口,so that enough。 若是自己节点可以完成任务,则将结果输出,终止传递。性能
用代码标识即为:this
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的冲动(不是写的烂,是写的太烂了),惟一可以表扬他的就是,知道职责链模式的原理。因此为了情怀,咱们须要给上面的代码换一身皮.prototype
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必须能明确的标识下一个到底继不继续。code
固然,要知道,这个职责链模式并非必定要把管理权交给内部执行,你固然也能够在外面进行判断和设置。接口
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指的是面向切面编程,即将其余函数动态的加入到一个函数中,好比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);
恩,以上结果只是一个简单地示范。 这里须要提个醒,职责链模式是设计模式中最容易忘记的模式之一,由于它好用到不叫模式。因此,职责链模式的用法也是不少的,但愿你们多多探索,将本身学到的只是分享出来,这是,极好的呀!