资讯专栏INFORMATION COLUMN

传递请求之职责链模式

wslongchen / 3303人阅读

摘要:想一想,这个和我们的迭代器模式有着异曲同工的妙处,迭代器模式同样也是遍历选出最优解,但是相比而言,职责链模式的直观性个书写的幸福感是远远超过迭代器模式的。

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

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

举个栗子吧:

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

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

恩,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);

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78510.html

相关文章

  • Java设计模式职责模式

    摘要:简介职责链模式有时候也叫责任链模式,它是一种对象行为的设计模式。中的就是使用了责任链模式。纯的责任链模式的实际例子很难找到,一般看到的例子均是不纯的责任链模式的实现。如果坚持责任链不纯便不是责任链模式,那么责任链模式便不会有太大意义了。 Java设计模式之职责链模式 前几天复习java的异常处理时,接触到了责任链模式。在企业级应用中,从前台发过来的请求在后台抛出异常,异常处理的设计一般...

    bergwhite 评论0 收藏0
  • JS每日一题:设计模式-如何理解职责模式?

    摘要:提交请求的对象并不明确知道哪一个对象将会处理它也就是该请求有一个隐式的接受者。 20190412期 设计模式-如何理解职责链模式? 定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止 也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者。提...

    lifesimple 评论0 收藏0
  • JavaScript设计模式----职责模式

    摘要:使用面向切面编程来快速的创建职责链的具体概念可以参考装饰者模式实现职责链简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能造成太大的影响。在开发中,职责链模式是最容易被忽视的模式之一。 声明:这个系列为阅读《JavaScript设计模式与开发实践》 ----曾探@著一书的读书笔记 1.职责链模式的定义 2. 2.1 简单职责链模式 2....

    boredream 评论0 收藏0
  • JS设计模式——职责模式

    摘要:用实现职责链这里使用变量存储上一个函数,存储的是最后一个调用返回的函数。理解了过程也就会知道这句代码是为后面的函数准备的建议如果某块功能中存在大量的可以考虑使用职责链模式 职责链模式 1. 职责链定义 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将对象连成一条链,并沿着这个链传递该请求,直到有一个对象处理它为止 2.职责链优点 请求发送者只需要知道链中的第一...

    piapia 评论0 收藏0
  • 一起学设计模式 - 责任模式

    摘要:责任链模式属于行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止。责任链模式通过将请求和处理分离开来,以进行解耦。源码分析我们经常使用的就使用到了责任链模式,创建一个除了要在应用中做相应配置外,还需要实现接口。 责任链模式(Chain Of Responsibility Pattern)属于行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止。 ...

    SoapEye 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<