使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止
优点:
- 解耦合:职责链模式的最大优点就是解耦了请求发送者和 N 个接收者之间的复杂关系(1对多 -> 1对1对1...)
- 任意起始点
- 组织代码
缺点:
- 多余的节点对象,用来帮助传递,并无实质性作用
- 性能:过长的职责链,会使调用栈的叠加,导致性能问题
假设我们负责一个售卖手机的电商网站,经过分别交纳 500 元定金和 200 元定金的两轮预定后(订单已在此时生成),现在已经到了正式购买的阶段。公司针对支付过定金的用户有一定的优惠政策。 在正式购买后,已经支付过 500 元定金的用 户会收到 100 元的商城优惠券,200 元定金的用户可以收到 50 元的优惠券, 而之前没有支付定金的用户只能进入普通购买模式,也就是没有优惠券,且在库存有限的情况下不一定保证能买到。
var order = function( orderType, pay, stock ){
if ( orderType === 1 ){ // 500 元定金购买模式
if ( pay === true ){ // 已支付定金
console.log( '500 元定金预购, 得到 100 优惠券' );
} else{ // 未支付定金,降级到普通购买模式
if ( stock > 0 ){ // 用于普通购买的手机还有库存
console.log( '普通购买, 无优惠券' );
}else{
console.log( '手机库存不足' );
}
}
} else if ( orderType === 2 ){
if ( pay === true ){ // 200 元定金购买模式
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); // 输出: 500 元定金预购, 得到 100 优惠券
var Chain = function( fn ){
this.fn = fn;
this.successor = null;
};
// 指定在链中的下一个节点
Chain.prototype.setNextSuccessor = function( successor ){
return this.successor = successor;
};
Chain.prototype.next = function( successor ){
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
};
// 传递请求给某个节点
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 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( '手机库存不足' );
return 'nextSuccessor'
}
};
var chainOrder500 = new Chain( order500 );
var chainOrder200 = new Chain( order200 );
var chainOrderNormal = new Chain( orderNormal );
var fn2 = new Chain(function(){
console.log( 2 );
var self = this;
setTimeout(function(){
self.next();
}, 1000 );
});
var fn3 = new Chain(function(){
console.log( 3 );
});
chainOrder500
.setNextSuccessor( chainOrder200 )
.setNextSuccessor( chainOrderNormal)
.setNextSuccessor( fn2 )
.setNextSuccessor( fn3 )
chainOrder500.passRequest(3, true, 0)
var fn1 = function(){
console.log( 1 );
return false;
}
var fn2 = function(){
console.log( 2 );
return false;
}
var fn3 = function(){
console.log( 3 );
return false;
}
Function.prototype.after = function( fn ){
var self = this;
return function() {
var ret = self.apply( this, arguments );
if ( ret === false ){
return fn.apply( this, arguments );
}
return ret;
}
};
var order = fn1.after( fn2 ).after( fn3 );
order();
用 AOP 来实现职责链既简单又巧妙,但这种把函数叠在一起的方式,同时也叠加了函数的 作用域,如果链条太长的话,也会对性能有较大的影响