职责链模式

Posted 小小坤

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了职责链模式相关的知识,希望对你有一定的参考价值。

简介

职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止。 也就是说,请求以后,从第一个对象开始,链中收到请求的对象要么亲自处理它,要么转发给链中的下一个候选者。提交请求的对象并不明确知道哪一个对象将会处理它——也就是该请求有一个隐式的接受者(implicit receiver)。根据运行时刻,任一候选者都可以响应相应的请求,候选者的数目是任意的,你可以在运行时刻决定哪些候选者参与到链中。

案例一

果伯伯在水果市场卖苹果,果果老板说:苹果分优质,中等,一般,给钱就卖四大类苹果。
优质苹果5元一斤,中等苹果4元一斤,一般苹果3元一斤,给钱就卖苹果1元一斤,一次最少卖一斤(这是例子,现实中不是这样的)
小明拿5元钱在这个摊上买1斤苹果,
小亮拿4元钱也在这个摊上买1斤苹果,
小帅拿3元钱也在这个摊上买1斤苹果,
小七拿1元钱也在这个摊上买1斤苹果,

分析: 小明、小亮、小帅、小七都是拿钱去买苹果的,他们就好比【一个个的请求】; 果伯伯的摊位就可以当做一个职责链,处理不同的买方请求。 苹果价位:price=5,4,3,1, 小明、小亮、小帅、小七的钱:people$=5,4,3,1

第一个版本:

/**
 * 买苹果
 * @name {string} 姓名
 * @price {Number} 价格
 * @weight {Number} 重量
 * 
 * */
function buyapple(name,price,weight){
    if(price==5){
        console.log(name+‘买到了5元1斤的苹果‘);
    }else if(price==4){
        console.log(name+‘买到了4元1斤的苹果‘);
    }else if(price==3){
        console.log(name+‘买到了3元1斤的苹果‘);
    }else if(price==1){
        console.log(name+‘买到了1元1斤的苹果‘);
    }
}
buyapple(‘小明‘,5,1);
buyapple(‘小亮‘,4,1);
buyapple(‘小帅‘,3,1);
buyapple(‘小七‘,1,1);

上述代码也许是最简单代码,最初级的程序员都会写,但是这样写的代码if嵌套比较多,更改维护比较费劲。假设又有2元一斤的苹果与用户,那就需要更改源码了。

第二个版本:

function buyapple5(name,price,weight){
    if(price==5){
       console.log(name+‘买到了5元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}
function buyapple4(name,price,weight){
    if(price==4){
       console.log(name+‘买到了4元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}
function buyapple3(name,price,weight){
    if(price==3){
       console.log(name+‘买到了3元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}
function buyapple1(name,price,weight){
    if(price==1){
       console.log(name+‘买到了1元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}

function Buyapple(fn){
    this.fn=fn;
    this.nextfn=null;//把下一个执行设置为null
}
Buyapple.prototype.setNextfn=function(nextfn){
    return this.nextfn=nextfn;//设置下一个执行的函数
}
Buyapple.prototype.Nextfn=function(){
   var res = this.fn.apply(this,arguments);//执行当前函数  
   if( res === "next" ){  
        //判断当前函数是否有下一个执行函数,有则执行
      return this.nextfn && this.nextfn.Nextfn.apply(this.nextfn,arguments);  
   }  
}

//现在我们吧3个订单函数分别包装成职责链的节点  
var chainOrder5 = new Buyapple(buyapple5);  
var chainOrder4 = new Buyapple(buyapple4); 
var chainOrder3 = new Buyapple(buyapple3)
var chainOrder1 = new Buyapple(buyapple1);  
//然后指定节点在指责链的顺序  
chainOrder5.setNextfn(chainOrder4);  
chainOrder4.setNextfn(chainOrder3);
chainOrder3.setNextfn(chainOrder1);
//最后传递请求  最上层,过滤数据执行
chainOrder5.Nextfn(‘小帅‘,3,1);

目前的职责链能够保证按照顺序执行下去。可以随意组合。但现在的代码只能保证是同步执行的。如果有异步中间执行代码则无法执行。

第三个版本:

function buyapple5(name,price,weight){
    if(price==5){
       console.log(name+‘买到了5元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}
function buyapple4(name,price,weight){
    var that=this;
    if(price==4){
       console.log(name+‘买到了4元1斤的苹果‘);
    }
    setTimeout(function(){
        console.log(‘等待两秒后执行‘);
        that.next(name,price,weight);
    },2000);

}
function buyapple3(name,price,weight){
    if(price==3){
       console.log(name+‘买到了3元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}
function buyapple1(name,price,weight){
    if(price==1){
       console.log(name+‘买到了1元1斤的苹果‘);
    }else{
        return ‘next‘;
    }
}

function Buyapple(fn){
    this.fn=fn;
    this.nextfn=null;//把下一个执行设置为null
}
Buyapple.prototype.setNextfn=function(nextfn){
    return this.nextfn=nextfn;//设置下一个执行的函数
}
Buyapple.prototype.Nextfn=function(){
   var res = this.fn.apply(this,arguments);//执行当前函数  
   if( res === "next" ){  
        //判断当前函数是否有下一个执行函数,有则执行
      return this.nextfn && this.nextfn.Nextfn.apply(this.nextfn,arguments);  
   }  
}
Buyapple.prototype.next=function(){
        //异步函数是无法返回next,只有借助next函数触发执行
      return this.nextfn && this.nextfn.Nextfn.apply(this.nextfn,arguments);  
}
//现在我们吧3个订单函数分别包装成职责链的节点  
var chainOrder5 = new Buyapple(buyapple5);  
var chainOrder4 = new Buyapple(buyapple4); 
var chainOrder3 = new Buyapple(buyapple3)
var chainOrder1 = new Buyapple(buyapple1);  
//然后指定节点在指责链的顺序  
chainOrder5.setNextfn(chainOrder4);  
chainOrder4.setNextfn(chainOrder3);
chainOrder3.setNextfn(chainOrder1);
//最后传递请求  最上层,过滤数据执行
chainOrder5.Nextfn(‘小帅‘,3,1);

connect框架next函数

var i=0,//索引
_arrycallback=[];//存储函数
//执行下一个函数
function next(){
    i++;
    _arrycallback[i] && _arrycallback[i]();
}
//存储next函数
function push_next(fn){
    _arrycallback.push(fn);
};

push_next(function(){
    console.log("1");
    next();
});
push_next(function(){
    setTimeout(function(){
        console.log("2","延迟500毫秒输出");
        next();
    },3000)

});
push_next(function(){
    console.log("3");
    next();
});
push_next(function(){
    console.log("4");
    next();
});
//执行
_arrycallback[0]();

Node.js 中大名鼎鼎的connect框架正是这样实现中间件队列的。有兴趣可以去看看它的源码或者这篇解读《何为 connect 中间件》。

总结

一:职责链模式的最大优点就是解耦了请求必送者和N个接收者之间的复杂关系,由于不知道链中的如个节点可以处理你发现的请求,所以你只需要请求传递给第一个节点即可。
二:使用了职责链模式之后,链中的节点对象可以灵活地拆分重组。增加或者删除一个节点,或者改变节点在链中的位置都是轻而易举的事情。
三:在职责模式还有一个优点,那就是可以手动指定起始节点,请求并不是非得从链中的第一个节点开始传递。
四:职责链模式使得程序中多了一些节点对象,可能在某一次的请求过程中,大部分节点并没有起到实质性的作用,它们的作用仅仅是让请求传递下去,从性能方面考虑,我们要避免过长的职责链带来性能损耗。
五:如果一个节点出错,就会导致整个链条断开。

 

以上是关于职责链模式的主要内容,如果未能解决你的问题,请参考以下文章

职责链模式vs状态模式区别

利用职责链模式分解If else

设计模式 行为型模式 -- 职责链模式(JDK源码分析:FilterChain(过滤器))

JAVA设计模式大总结(二十三)--- b站尚硅谷设计模式之 职责链模式 图解 + 代码 整理(超详)

职责链模式

职责链模式分析结构图与基本代码