职责链模式

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

假设我们负责一个售卖手机的电商网站,经过分别交纳 500 元定金和 200 元定金的两轮预定 后(订单已在此时生成),现在已经到了正式购买的阶段。

公司针对支付过定金的用户有一定的优惠政策。在正式购买后,已经支付过 500 元定金的用 户会收到 100 元的商城优惠券,200 元定金的用户可以收到 50 元的优惠券,而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到。

将这个流程变成代码如下所示:

// orderType 表示订单类型
// 值为1时表示500元定金用户,值为2时表示200元定金用户,值为3时表示普通用户
// pay表示用户是否支付定金,true表示已经支付,false表示没有支付
// stock表示当前用于普通购买的手机库存数量,已经支付过500元或者200元定金的用户不受此限制
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('手机库存不足');
        }
    }
}

但是这段代码过于巨大,难以修改,不利于维护。使用职责链可以将这个函数拆分成500元定金函数,200元定金函数,普通用户函数,接下来把 orderType、pay、stock 这 3 个字段当作参数传递给 500 元订单函数,如果该函数不 符合处理条件,则把这个请求传递给后面的 200 元订单函数,如果 200 元订单函数依然不能处理 该请求,则继续传递请求给普通购买函数,代码如下:

var order500 = function( orderType, pay, stock ) {
    if (orderType === 1 && pay === true){ 
        console.log( '500 元定金预购,得到 100 优惠券' ); 
    } else { 
        return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
    } 
}; 

var order200 = function( orderType, pay, stock ) {
    if (orderType === 2 && pay === true) { 
        console.log( '200 元定金预购,得到 50 优惠券' ); 
    } else { 
        return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递 
    } 
}; 

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

接下来需要把函数包装进职责链节点,我们定义一个构造函数 Chain,在 new Chain 的时候传 递的参数即为需要被包装的函数,同时它还拥有一个实例属性 this.successor,表示在链中的下 一个节点。

// Chain.prototype.setNextSuccessor 指定在链中的下一个节点
// Chain.prototype.passRequset 传递请求给某个节点

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;
};

现在我们把 3 个订单函数分别包装成职责链的节点:

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

然后指定节点在职责链中的顺序:

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

最后把请求传递给第一个节点:

chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到 100 优惠券 
chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到 50 优惠券 
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券 
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足

我们可以利用 JavaScript 的函数式特性,有一种更加方便的方法来创建职责链。

Function.prototype.after = function (fn) {
    var self = this;

    return function() {
        var ret = self.apply(this, arguments);
        
        if (ret === 'nextSuccessor') {
            return fn.apply(this, argument);
        }

        return ret;
    }
};

var order = order500.after(order200).after(orderNormal);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值