资讯专栏INFORMATION COLUMN

JavaScript设计模式----职责链模式

boredream / 3433人阅读

摘要:使用面向切面编程来快速的创建职责链的具体概念可以参考装饰者模式实现职责链简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能造成太大的影响。在开发中,职责链模式是最容易被忽视的模式之一。

声明:这个系列为阅读《JavaScript设计模式与开发实践》 ----曾探@著一书的读书笔记

1.职责链模式的定义

2.

2.1 简单职责链模式

2.2职责链重构上面的代码

2.3灵活的拆分职责链节点

3.异步职责链

4.职责链模式的优缺点:

5.使用AOP(面向切面编程)来快速的创建职责链

总结:

1.职责链模式的定义

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

2. 2.1 简单职责链模式

故事背景:用户可以支付定金购买手机,并且可以获得优惠券。没有支付定金的就是普通用户,进入普通购买模式,没有优惠券,且库存不足的情况下不一定能够买到手机。

/**
 *
 * @param orderType 订单类型
 * @param pay   用户是否已经支付过定金 true or false
 * @param stock 表示手机的库存量
 */
var order = function (orderType, pay, stock){
    if (orderType === 1) {
        if (pay === true) {
            console.log("500定金预购,得到100元优惠券");
        }
        else {
            if (stock > 0) {
                console.log("普通购买,没有优惠券");
            }
            else {
                console.log("手机库存不足");
            }
        }
    }
    else if (orderType === 2) {
        if (pay === true) {
            console.log("200定金预购,得到50元优惠券");
        }
        else {
            if (stock > 0) {
                console.log("普通购买,没有优惠券");
            }
            else {
                console.log("手机库存不足");
            }
        }
    }
    else if (orderType === 3) {
        if (stock > 0) {
            console.log("普通购买,没有优惠券");
        }
        else {
            console.log("手机库存不足");
        }
    }
};
2.2职责链重构上面的代码

主要通过拆分功能语句,来使用职责链重构:

//500元订单
var order500 = function (orderType, pay, stock){
    if (orderType === 1 && pay === true) {
        console.log("500定金预购,得到100元优惠券");
    }
    else {
        order200(orderType, pay, stock);  //将请求传递给200
    }
};

//200元订单
var order200 = function (orderType, pay, stock){
    if (orderType === 2 && pay === true) {
        console.log("200定金预购,得到50元优惠券");
    }
    else {
        order(orderType, pay, stock);
    }
};

//普通购买订单
var order = function (orderType, pay, stock){
    if (stock>0) {
        console.log("普通购买,没有优惠券");
    }
    else {
    console.log("手机库存不足");
    }
};

//测试调用
order500(1,true,500);
order500(3,false,0);

总结:
上面的代码违反了开放-封闭的原则,请求在链条中传递的顺序非常僵硬,传递请求的代码被耦合在了业务函数中:

var order500 = function (orderType, pay, stock){
    if (orderType === 1 && pay === true) {
        console.log("500定金预购,得到100元优惠券");
    }
    else {
        order200(orderType, pay, stock);  //将请求传递给200
    }
};
2.3灵活的拆分职责链节点

为什么要拆分职责链的节点,因为某天需要添加新的职责,就需要修改业务代码(要修改的话,就需要先去了解他,熟悉它,花费大量的时间)。这显然不是每一个人所需要的。

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

//200元订单
var order200 = function (orderType, pay, stock){
    if (orderType === 2 && pay === true) {
        console.log("200定金预购,得到50元优惠券");
    }
    else {
        return "nextSuccessor";
    }
};

//普通购买订单
var order = function (orderType, pay, stock){
    if (stock>0) {
        console.log("普通购买,没有优惠券");
    }
    else {
        console.log("手机库存不足");
    }
};

var Chain=function (fn){
    this.fn=fn;
    this.successor=null;
};

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

Chain.prototype.passRequest=function(){
    var ret= this.fn.apply(this,arguments);

    if(ret==="nextSuccessor"){
        return this.successor && this.successor.passRequest.apply(this.successor,arguments);
    }

    return ret;
};

var chainOrder500=new Chain(order500());
var chainOrder200=new Chain(order200());
var chainOrderNormal=new Chain(order());

chainOrder500.setNextSuccessor(chainOrder200);
chainOrder200.setNextSuccessor(chainOrderNormal);

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

加入某天网站添加了300元定金购买的职责,我只需要添加特定的节点就可以了:

//300元订单
var order300=function (){

};

var chainOrder300=new Chain(order300());
chainOrder500.setNextSuccessor(chainOrder300);
chainOrder500.setNextSuccessor(chainOrder200);

这样的话只需要编写简单的功能函数,改变职责链中的相关节点的顺序即可。

3.异步职责链

上面的职责链代码中,每个节点函数同步返回一个特定的值nextSuccessor,来表示是否把请求传递给下一个节点。而现实开发中会遇到一些异步的问题,比如在一个节点中发起一个ajax异步请求,异步请求的结果才能决定是否继续在职责链中passRequest

可以给Chain类添加一个原型方法Chain.prototype.next,表示手动传递请求给职责链中的下一个节点:

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



//异步职责链的例子
var fn1=new Chain(function (){
    console.log(1);
    return "nextSuccessor";
});

var fn2=new Chain(function (){
    console.log(2);
    var self=this;
    setTimeout(function (){
        self.next();
    },1000);

});

var fn3=new Chain(function (){
    console.log(3);

});

fn1.setNextSuccessor(fn2).setNextSuccessor(fn3);
fn1.passRequest();
4.职责链模式的优缺点:

优点:

职责链最大的优点就是解耦了请求发送者和N个接收者之间的复杂关系。

职责链可以手动指定起始节点,请求并不是非得从链中的第一个节点开始传递。

缺点:

不能保证某个请求一定会被链中的节点处理,这种情况可以在链尾增加一个保底的接受者节点来处理这种即将离开链尾的请求。

使程序中多了很多节点对象,可能再一次请求的过程中,大部分的节点并没有起到实质性的作用。他们的作用仅仅是让请求传递下去,从性能当面考虑,要避免过长的职责链到来的性能损耗。

5.使用AOP(面向切面编程)来快速的创建职责链

AOP的具体概念可以参考装饰者模式

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

        return ret;
    }
};


var order=order500yuan.after(order200yuan).after(orderNormal);

order(1,true,500);
order(1,false,500);

AOP实现职责链简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的作用域,如果链条太长的话,也会对性能造成太大的影响。

总结:

职责链模式最大的优点:请求发送者只需要知道链中的第一个节点,从而弱化了发送者和一组接收者之前的强联系。

在JavaScript开发中,职责链模式是最容易被忽视的模式之一。但是只要运用得当,职责链模式可以很好的帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。且职责链中节点的数量和数序是可以自由变化的。可以在运行时决定链中包含哪些节点。

无论是作用域链,原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链模式的影子。

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

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

相关文章

  • 前端开发中常用的javascript设计模式

    摘要:代理模式,迭代器模式,单例模式,装饰者模式最少知识原则一个软件实体应当尽可能少地与其他实体发生相互作用。迭代器模式可以将迭代的过程从业务逻辑中分离出来,在使用迭代器模式之后,即不用关心对象内部构造也可以按顺序访问其中的每个元素。 接手项目越来越复杂的时候,有时写完一段代码,总感觉代码还有优化的空间,却不知道从何处去下手。设计模式主要目的是提升代码可扩展性以及可阅读性。 本文主要以例子的...

    赵春朋 评论0 收藏0
  • javascript设计模式--装饰者模式

    摘要:装饰者模式定义装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。 装饰者模式 定义 : 装饰者(decorator)模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。 在不改变对象自身的基础上,在程序运行期间给对象动态地添加一些额外职责 特点 : 可以动态的...

    haoguo 评论0 收藏0
  • JavaScript设计模式与开发实践》读书笔记

    摘要:订阅模式的一个典型的应用就是后面会写一篇相关的读书笔记。享元模式享元模式的核心思想是对象复用,减少对象数量,减少内存开销。适配器模式对目标函数进行数据参数转化,使其符合目标函数所需要的格式。 设计模式 单例模式 JS的单例模式有别于传统面向对象语言的单例模式,js作为一门无类的语言。使用全局变量的模式来实现单例模式思想。js里面的单例又分为普通单例和惰性单例,惰性单例指的是只有这个实例...

    Panda 评论0 收藏0
  • JavaScript常用的设计模式

    摘要:前言设计模式几十种,阅读了设计模式与开发实践这本书后,个人感觉就是围绕对象来设计的,发现日常写代码能用上的并不多,下面是常用的几种设计模式。前端服务端可以参考我的另一个仓库地址,一个简单的实时聊天参考来自设计模式与开发实践读书笔记 前言 设计模式几十种,阅读了《JavaScript设计模式与开发实践》这本书后,个人感觉js就是围绕对象来设计的,发现日常写代码能用上的并不多,下面是常用的...

    mengbo 评论0 收藏0
  • 传递请求之职责模式

    摘要:想一想,这个和我们的迭代器模式有着异曲同工的妙处,迭代器模式同样也是遍历选出最优解,但是相比而言,职责链模式的直观性个书写的幸福感是远远超过迭代器模式的。 职责链模式其实很好理解,由于一个链字出卖了它的灵魂。我们可以从这个字得到很大的提示。首先这个模式一定有传递性,而且,节点是可以重复拼接的,并且每个节点都具有一定的过滤功能,一定的职责。 是不是想起了组合模式里的一些内容呢? 是的,他...

    wslongchen 评论0 收藏0

发表评论

0条评论

boredream

|高级讲师

TA的文章

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