基本实现流程如下:
1.发送者知道链中的第一个接收者,它向这个接收者发送该请求。
2.每一个接收者都对请求进行分析,然后要么处理它,要么它往下传递。
3.每一个接收者知道其他的对象只有一个,即它在链中的下家(successor)。
4.如果没有任何接收者处理请求,那么请求会从链中离开。
下面列举个列子来说明职责链的好处:
天猫每年双11都会做抽奖活动的,比如阿里巴巴想提高大家使用支付宝来支付的话,每一位用户充值500元到支付宝的话,那么可以100%中奖100元红包,
充值200元到支付宝的话,那么可以100%中奖20元的红包,当然如果不充值的话,也可以抽奖,但是概率非常低,基本上是抽不到的,当然也有可能抽到的。
我们下面可以分析下代码中的几个字段值需要来判断:
orderType(充值类型),如果值为1的话,说明是充值500元的用户,如果为2的话,说明是充值200元的用户,如果是3的话,说明是没有充值的用户。
isPay(是否已经成功充值了): 如果该值为true的话,说明已经成功充值了,否则的话 说明没有充值成功;就当作普通用户来购买。
count(表示数量);普通用户抽奖,如果数量有的话,就可以拿到优惠卷,否则的话,不能拿到优惠卷。
function order500(orderType,isPay,count){
if(orderType == 1 && isPay == true) {
console.log("亲爱的用户,您中奖了100元红包了");
}else {
//我不知道下一个节点是谁,反正把请求往后面传递
return "nextSuccessor";
}
};
function order200(orderType,isPay,count) {
if(orderType == 2 && isPay == true) {
console.log("亲爱的用户,您中奖了20元红包了");
}else {
//我不知道下一个节点是谁,反正把请求往后面传递
return "nextSuccessor";
}
};
function orderNormal(orderType,isPay,count){
// 普通用户来处理中奖信息
if(count > 0) {
console.log("亲爱的用户,您已抽到10元优惠卷");
}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;
}
//现在我们把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); // 亲爱的用户,您中奖了100元红包了
chainOrder500.passRequest(2,true,500); // 亲爱的用户,您中奖了20元红包了
chainOrder500.passRequest(3,true,500); // 亲爱的用户,您已抽到10元优惠卷
chainOrder500.passRequest(1,false,0); // 亲爱的用户,请再接再厉哦
理解异步的职责链
上面的只是同步职责链,我们让每个节点函数同步返回一个特定的值”nextSuccessor”,来表示是否把请求传递给下一个节点,在我们开发中会经常碰到ajax异步请求,请求成功后,需要做某某事情,那么这时候如果我们再套用上面的同步请求的话,就不生效了,下面我们来理解下使用异步的职责链来解决这个问题;我们给Chain类再增加一个原型方法Chain.prototype.next,表示手动传递请求给职责链中的一下个节点。
如下代码:
function Fn1() {
console.log(1);
return "nextSuccessor";
}
function Fn2() {
console.log(2);
var self = this;
setTimeout(function(){
self.next();
},1000);
}
function Fn3() {
console.log(3);
}
// 下面需要编写职责链模式的封装构造函数方法
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;
}
Chain.prototype.next = function(){
return this.successor && this.successor.passRequest.apply(this.successor,arguments);
}
//现在我们把3个函数分别包装成职责链节点:
var chainFn1 = new Chain(Fn1);
var chainFn2 = new Chain(Fn2);
var chainFn3 = new Chain(Fn3);
// 然后指定节点在职责链中的顺序
chainFn1.setNextSuccessor(chainFn2);
chainFn2.setNextSuccessor(chainFn3);
chainFn1.passRequest(); // 打印出1,2 过1秒后 会打印出3
调用函数 chainFn1.passRequest();后,会先执行发送者Fn1这个函数 打印出1,然后返回字符串 nextSuccessor;
接着就执行return this.successor && this.successor.passRequest.apply(this.successor,arguments);这个函数到Fn2,打印2,接着里面有一个setTimeout定时器异步函数,需要把请求给职责链中的下一个节点,因此过一秒后会打印出3;