zoukankan      html  css  js  c++  java
  • 职责链模式

    简介

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

  • 相关阅读:
    MSDN Magazine搞错了
    Visual Studio 2005中设置调试符号(Debug Symbols)
    BCB 6的问题
    吴裕雄天生自然Spring Boot使用Spring Data JPA实现人与身份证的一对一关系映射
    吴裕雄天生自然Spring BootSpring Data JPA
    吴裕雄天生自然Spring BootSpring Boot对JSP的支持
    吴裕雄天生自然Spring BootSpring Boot的异常统一处理
    吴裕雄天生自然Spring Boot使用Spring Data JPA实现Author与Article的一对多关系映射
    吴裕雄天生自然Spring Boot解决 Error creating bean with name 'entityManagerFactory' defined in class path resource
    吴裕雄天生自然Spring Boot@ExceptionHandler注解和@ControllerAdvice注解
  • 原文地址:https://www.cnblogs.com/xiaoxiaokun/p/7650091.html
Copyright © 2011-2022 走看看