责任链模式定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式的优点:
1、解耦了请求的发送者和多个接收者之前的复杂关系
2、方便链路中的节点对象灵活的拆分重组
3、手动指定起始节点,可以不是从链路中第一个节点开始
案例1:解决一大堆多层if-else包裹问题
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 ){ // 200 元定金购买模式
if ( pay === true ){
console.log( '200 元定金预购, 得到 50 优惠券' );
}else{
if ( stock > 0 ){
console.log( '普通购买, 无优惠券' );
}else{
console.log( '手机库存不足' );
}
}
}
//else if ( orderType === 3 ){..........};
order( 1 , true, 500);
用责任链模式优化后
//首先定义不同责任链节点的方法
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( '手机库存不足' );
}
};
//定义责任链
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;
};
//创建节点
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 );
案例2:责任链模式获得文件上传对象
//封装一个责任链公告方法
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 getActiveUploadObj = function(){
try{
return new ActiveXObject("TXFTNActiveX.FTNUpload"); // IE 上传控件
}catch(e){
return 'nextSuccessor' ;
}
};
var getFlashUploadObj = function(){
if ( supportFlash() ){
return document.createElement( '<object type="application/x-shockwave-flash"></object>');
}
return 'nextSuccessor' ;
};
var getFormUpladObj = function(){
return document.createElement( '<form><input name="file" type="file"/></form>')
};
var getUploadObj = getActiveUploadObj.after( getFlashUploadObj ).after( getFormUpladObj );
console.log( getUploadObj() );
在js的设计中,无论是作用域链、原型链,还是 DOM 节点中的事件冒泡,我们都能从中找到职责链模式的影子,所以在责任链模式的思想其实在前端比较重要。