js设计模式之职责链模式

一. 初始职责链模式

        定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者的关系,将这个对象连成一条链,并沿着一条链传递该请求,直到一个对象处理它为止。

可能有点晦涩难懂,我门来看一个例子,比如说你妈让你出去打酱油,此时我的请求就是买一瓶酱油回来,你会出门先去离你家最近的超市买酱油,如果没有,你会去下一个超市,知道有一个超市买到了酱油,也就结束了这条链的传递,超市就相当于处理请求的一条对象链,这就是职责链模式,我们想办法用代码实现它。

二. 代码实现

需求:我们来实现生活中的一个例子,商品的优惠活动,有三种情况,第一种是500元订金100元优惠券,第二种是200元订金50元优惠券,第三种是无优惠。

        此时我们首先想到的做法肯定使用条件分支来判断属于哪一种优惠,虽然可以达到目的,但是代码的可维护性太低,我们可以使用职责链模式来实现。

1. 灵活可拆分的职责链节点

        分析:首先我们将每一次优惠作为单独封装,判断请求是否满足此次优惠条件,如果不满足,则向下传递,直到满足优惠条件为止。

        let order500 = function( orderType, pay, stock ) {
            if( orderType == 1 && pay == true) {
                console.log(" 500元订金,得到100元优惠券");
            }else{
                return 'nextSuccessor';
            }
        }

        let order200 = function( orderType, pay, stock ){

            if( orderType == 2 && pay == true ) {
                console.log(" 200元订金,得到50元优惠券");
            }else{
                return 'nextSuccessor';
            }
        }

        let orderNormal = function( orderType, pay, stock ) {
            if(stock > 0) {
                console.log("普通购买,无优惠券");
            }else{
                console.log("手机库存不足");
            }
        }

        // 包装节点
        let Chain = function( fn ){
            this.fn = fn;
            this.successor = null;
        }

        Chain.prototype.setNextSuccessor = function( successor ) {
            return this.successor = successor;
        }

        Chain.prototype.passRequest = function() {
            let ret = this.fn.apply(this, arguments);
            if( ret === "nextSuccessor") {
                return this.successor && this.successor.passRequest.apply(this.successor, arguments);
            }
            return ret;
        }

        // 创建职责链节点

        let chainOrder500 = new Chain( order500 );
        let chainOrder200 = new Chain( order200 );
        let chainOrderNormal = new Chain( orderNormal );
        
        chainOrder500.setNextSuccessor( chainOrder200 ).setNextSuccessor(chainOrderNormal);


        chainOrder500.passRequest(1, true, 500);
        chainOrder500.passRequest(2, true, 500);

2. 异步的职责链

        分析:有时我们的请求可能不是那么顺畅,比如获取请求时,请求数据拿回来可能有延迟,我们根据拿到的数据来判断是否进行再次的请求,因此我们需要设置主动向下一节点传递请求,通过异步实现。

        // 包装节点
        let Chain = function( fn ){
            this.fn = fn;
            this.successor = null;
        }

        Chain.prototype.setNextSuccessor = function( successor ) {
            return this.successor = successor;
        }

        Chain.prototype.passRequest = function() {
            let ret = this.fn.apply(this, arguments);
            if( ret === "nextSuccessor") {
                return this.successor && this.successor.passRequest.apply(this.successor, arguments);
            }
            return ret;
        }

        Chain.prototype.next = function() {
            return this.successor && this.successor.passRequest.apply( this.successor, arguments);
        }

        // 创建职责链节点

        let fn1 = new Chain(()=>{
            console.log(1);
            return 'nextSuccessor';
        })
        let fn2 = new Chain(function(){
            console.log(2);
            let self = this;
            setTimeout(()=>{
                self.next();
            }, 2000);
        })

        let fn3 = new Chain(()=>{
            console.log(3);
        })

        fn1.setNextSuccessor( fn2 ).setNextSuccessor( fn3 );
        fn1.passRequest();

3. 用 AOP 实现职责链

分析:用 AOP 来实现虽然简单巧妙,但是将函数叠在一起,也叠加了函数的作用域,如果两天太长会对性能有较大影响。

        Function.prototype.after = function( fn ) {
            let self = this;
            return function() {
                let ret = self.apply(this, arguments);
                if(ret === 'nextSuccessor') {
                    fn.apply( this, arguments );
                }
                return ret;
            }
        }

        let order = order500.after( order200 ).after( orderNormal );
        order(3, true, 500);

三. 总结

        优点:1.  解耦了请求的发送者和 N 哥接收者之间的 复杂关系

                   2. 每个对象可有灵活拆分,控制请求的入口和长度

        缺点: 1. 可能某次传递中大部分节点都只是作为传递,并没有多大的用处,造成性能损耗

无论是作用域链,原型链,还是冒泡事件中都合适的应用了职责链模式。职责链模式还可以和组合模式结合在一起,用来连接部件和父部件,或者提高组合对象的效率。

上一篇:leaflet结合PostGIS动态渲染矢量瓦片(附源码下载)


下一篇:PostGIS 安装