职责链模式定义
职责链模式是指解决请求发送者和请求的接受者之间的耦合,通过职责链上的多个对象对分解请求流程,实现请求在多个对象之间的传递,直到最后一个对象完成请求的处理。
职责链模式通过对需求的分解,把每件事情独立出一个模块对象去处理,这样完整的需求就被分解成一部分一部分相互独立的模块需求,通过这些对象的分工协作,每个对象只做与自己份内的事,无关的事传到下一个对象中去做,直到需求完成。
职责链模式实例
假设某电商网站对支付定金的客户有优惠活动,支付500定金可以获取100元优惠券,支付200定金可以获取50元优惠券,而没有支付定金的客户没有优惠券,并且在库存有限时不一定能买到。
我们先用3个函数来分别表示3种购买模式的节点函数,如果某个节点不能处理请求,则返回一个特定字符串nextSuccessor
来表示该请求需要继续往后面传递:
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 order0 = function(orderType,pay,stock){
if(stock > 0) {
console.log("普通购买");
}else {
console.log("库存不足");
}
}
接下来,我们定义一个构造函数chain,在new chain时将要被包装的函数传递进来,同时设置一个successor的属性用来指定链的下一个节点。
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 chain500 = new chain(order500);
var chain200 = new chain(order200);
var chain0 = new chain(order0);
chain500.setNextSuccessor(chain200);
chain200.setNextSuccessor(chain0);
chain500.passRequest(1,true,900); //已支付500元定金,获得100元优惠券
chain500.passRequest(2,true,500); //已支付200元定金,获得50元优惠券
chain500.passRequest(2,false,0); //库存不足
在开发中,我们有时候会遇到异步的情况,例如ajax异步请求,异步请求返回的结果才能决定是否继续在职责链中passRequest。这时候需要给chain增加一个next方法,手动传递请求给职责链的下一个节点:
chain.prototype.next = function(){
return this.successor && this.successor.passRequest.apply(this.successor,arguments);
}
var f1 = new chain(function(){
console.log("f1");
return "nextSuccessor";
})
var f2 = new chain(function(){
var _this = this;
console.log("f2");
setTimeout(function(){
_this.next();
},1000);
})
var f3 = new chain(function(){
console.log("f3");
})
f1.setNextSuccessor(f2).setNextSuccessor(f3);
f1.passRequest();
小结
职责链模式优点
- 解耦了请求发送者和N个接收者之间的复杂关系,由于不知道链中哪个节点可以处理你发出的请求,所以只需要把请求传递给第一个节点即可。
- 使用了职责链模式后,链中的节点对象可以灵活地拆分重组。增加或删除一个节点,或者改变节点在链中位置都是轻而易举的事情。
- 可以手动指定起始节点,请求并不是非得从链中的第一个节点传递。
职责链模式缺点
- 不能保证某个请求一定会被链中的节点处理。在这种情况下,我们可以在链尾增加一个保底的接受者节点来处理这种即将离开链尾的请求。
- 职责链模式使得程序中多了一些节点对象,可能在某一次的请求传递过程中,大部分节点并没有起到实质性的作用,他们的作用仅仅是让请求传递下去,从性能方面考虑,我们要避免过长的职责链带来的性能损耗。