JavaScript设计模式之职责链

责任链

什么是责任链

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

  • 举个栗子:
    • 当公交车很挤的时候,你从后门上车,这个时候你不可能直接把硬币放到收款箱里面, 因为你不知道它在哪,那你就只能把硬币给你前面一个人,让他帮你传到前面一个人手上,这样一直传递到站在收款箱旁边人的手上,由他把硬币放到收款箱里面。

JavaScript实现职责链模式

Function.prototype.after = function(fn) {
 var _self = this;
 return function () {
   // 将self的执行上下文改成window并执行函数
   var ret = _self.apply(this, arguments);
   // 如果函数的返回值是 nextSuccessor 则执行传参函数
   if(ret === "nextSuccessor") {
   // 将fn的执行上下文改成window并执行函数
    return fn.apply(this, arguments);
   }
   return ret;
 }
}

在函数执行之后确定是否执行下一个函数,你每次调用after,都相当于在已有函数之后添加一个函数,至于是否执行后面这个函数,取决于前一个函数的返回值。

示例

假设这么一个场景:
一个售卖手机的电商网站,经过分别缴纳500元定金和200元定金的两轮预定后,到了正式购买阶段。针对预定用户实行优惠,支付过500元定金的用户会收到100元的商城优惠券,支付过200元定金的用户会收到50元的商城优惠券,没有支付定金的用户归为普通购买,且在库存有限的情况下不一定保证买到。

传统方式实现

/* 传统方式实现 */
// orderType:[1:500, 2:200, 3:普通],isPaid:true/false,stock:库存量
var order = function(orderType, isPaid, stock) {
    if(orderType === 1) {
        if(isPaid) {
            console.log("500元定金预购,得到100优惠券");
        } else {
            if(stock > 0) {
                console.log("普通购买,无优惠券");
            }else {
                console.log("库存不足");
            }
        }
    }else if(orderType === 2) {
        if(isPaid) {
            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("库存不足");
        }
    }
}

order(1, true, 500);

可以看到耦合性相当的高,orderType === 3条件下的代码在orderType === 1orderType === 2条件下都有用到。而且当还有另一种又会方案的时候,需要修改order()的内容。当增加多种方案之后order()内将会有很多ifelse if。这样的代码相当难看。

责任链方式实现

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

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

// orderType === 3的情况,也是默认其他种乱输入的情况
var orderNormal = function(orderType, isPaid, stock) {
    if(stock > 0) {
        console.log("普通购买,无优惠券");
    }else {
        console.log("库存不足");
    }
};

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 = order500.after(order200).after(orderNormal);
order(1, true, 10);

优缺点

优点

  • 降低耦合度
  • 动态组合职责
    • 责任链模式会把功能处理分散到单独的职责对象中,然后在使用的时候,就可以动态组合职形成职责链,从而可以灵活地给对象分配职责,也可以灵活地实现和改变对象的职责。

缺点

  • 不能保证某个请求一定会被链中的节点处理
    • 责任链模式的每个职责对象只负责处理自己处理的那部分,因此可能会出现某个请求,把整个责任链传递完也没有职责对象处理它。这就需要在使用责任链的时候,需要提供默认的处理。

我的项目通过责任链修改

##没有使用责任链前

if (value === 'check') {
    /* 是否输入确认密码了 */
    if (!this.checkPassword) {
        this.inputErrorMessage('errorCheck', 'errorCheckText', '请确认密码')
        return false
    }
    /* 两次密码是否一致 */
    if (this.password !== this.checkPassword) {
        this.inputErrorMessage('errorCheck', 'errorCheckText', '两次密码输入不一致')
        return false
    }
    this.errorCheck = false
} else if (value === 'pass') {
    /* 是否输入密码了 */
    if (!this.password) {
        this.inputErrorMessage('errorPass', 'errorPassText', '请输入密码')
        return false
    }
    /* 密码格式是否正确 */
    let reg = /(?!^(\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\w~!@#$%&*?/]+$/
    if (!reg.test(this.password)) {
        this.inputErrorMessage('errorPass', 'errorPassText', '请输入正确密码格式')
        return false
    }
    // 输入确认密码后又修改密码
    if (this.password !== this.checkPassword) {
        if (this.checkPassword) {
            this.inputErrorMessage('errorCheck', 'errorCheckText', '两次密码输入不一致')
        }
    } else {
        this.errorCheck = false
    }
    this.errorPass = false
}

使用责任链

    passwordFunc (value) {
      if (value === 'pass' && !this.password) {
        this.inputErrorMessage('errorPass', 'errorPassText', '请输入密码')
      } else {
        return 'nextSuccessor'
      }
    },
    passVerifyFunc (value) {
      let reg = /(?!^(\d+|[a-zA-Z]+|[~!@#$%^&*?]+)$)^[\w~!@#$%&*?/]+$/
      if (value === 'pass' && !reg.test(this.password)) {
        this.inputErrorMessage('errorPass', 'errorPassText', '请输入正确密码格式')
      } else {
      	if (value === 'pass') {
          this.errorPass = false
      	}
        return 'nextSuccessor'
      }
    },
    samePassFunc (value) {
      if (this.password !== this.checkPassword && this.password && this.checkPassword) {
        this.inputErrorMessage('errorCheck', 'errorCheckText', '两次密码输入不一致')
      } else {
        return 'nextSuccessor'
      }
    },
    checkPassFunc (value) {
      if (value === 'check' && !this.checkPassword) {
        this.inputErrorMessage('errorCheck', 'errorCheckText', '请确认密码')
      } else {
        return 'nextSuccessor'
      }
    },
    checkOKFunc (value) {
      this.errorCheck = false
    },
    handlePasswordCheck (value) {
      let order = this.passwordFunc.after(this.passVerifyFunc).after(this.samePassFunc).after(this.checkPassFunc).after(this.checkOKFunc)
      order(value)
    }

有点点复杂…不是所有的if-else都适合用这个设计模式。所以打算去学习其他的设计模式了呢~

文章有引用一篇我之前看过的但是忘了地址的文章了,不过这只是我的笔记啦~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值