一. 初始职责链模式
定义:使多个对象都有机会处理请求,从而避免请求的发送者和接收者的关系,将这个对象连成一条链,并沿着一条链传递该请求,直到一个对象处理它为止。
可能有点晦涩难懂,我门来看一个例子,比如说你妈让你出去打酱油,此时我的请求就是买一瓶酱油回来,你会出门先去离你家最近的超市买酱油,如果没有,你会去下一个超市,知道有一个超市买到了酱油,也就结束了这条链的传递,超市就相当于处理请求的一条对象链,这就是职责链模式,我们想办法用代码实现它。
二. 代码实现
需求:我们来实现生活中的一个例子,商品的优惠活动,有三种情况,第一种是500元订金100元优惠券,第二种是200元订金50元优惠券,第三种是无优惠。
此时我们首先想到的做法肯定使用条件分支来判断属于哪一种优惠,虽然可以达到目的,但是代码的可维护性太低,我们可以使用职责链模式来实现。
1. 灵活可拆分的职责链节点
分析:首先我们将每一次优惠作为单独封装,判断请求是否满足此次优惠条件,如果不满足,则向下传递,直到满足优惠条件为止。
let order500 = function( orderType, pay, stock ) {
if( orderType == 1 && pay == true) {
console.log(" 500元订金,得到100元优惠券");
}else{
return 'nextSuccessor';
}
}
let order200 = function( orderType, pay, stock ){
if( orderType == 2 && pay == true ) {
console.log(" 200元订金,得到50元优惠券");
}else{
return 'nextSuccessor';
}
}
let orderNormal = function( orderType, pay, stock ) {
if(stock > 0) {
console.log("普通购买,无优惠券");
}else{
console.log("手机库存不足");
}
}
// 包装节点
let Chain = function( fn ){
this.fn = fn;
this.successor = null;
}
Chain.prototype.setNextSuccessor = function( successor ) {
return this.successor = successor;
}
Chain.prototype.passRequest = function() {
let ret = this.fn.apply(this, arguments);
if( ret === "nextSuccessor") {
return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}
return ret;
}
// 创建职责链节点
let chainOrder500 = new Chain( order500 );
let chainOrder200 = new Chain( order200 );
let chainOrderNormal = new Chain( orderNormal );
chainOrder500.setNextSuccessor( chainOrder200 ).setNextSuccessor(chainOrderNormal);
chainOrder500.passRequest(1, true, 500);
chainOrder500.passRequest(2, true, 500);
2. 异步的职责链
分析:有时我们的请求可能不是那么顺畅,比如获取请求时,请求数据拿回来可能有延迟,我们根据拿到的数据来判断是否进行再次的请求,因此我们需要设置主动向下一节点传递请求,通过异步实现。
// 包装节点
let Chain = function( fn ){
this.fn = fn;
this.successor = null;
}
Chain.prototype.setNextSuccessor = function( successor ) {
return this.successor = successor;
}
Chain.prototype.passRequest = function() {
let 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);
}
// 创建职责链节点
let fn1 = new Chain(()=>{
console.log(1);
return 'nextSuccessor';
})
let fn2 = new Chain(function(){
console.log(2);
let self = this;
setTimeout(()=>{
self.next();
}, 2000);
})
let fn3 = new Chain(()=>{
console.log(3);
})
fn1.setNextSuccessor( fn2 ).setNextSuccessor( fn3 );
fn1.passRequest();
3. 用 AOP 实现职责链
分析:用 AOP 来实现虽然简单巧妙,但是将函数叠在一起,也叠加了函数的作用域,如果两天太长会对性能有较大影响。
Function.prototype.after = function( fn ) {
let self = this;
return function() {
let ret = self.apply(this, arguments);
if(ret === 'nextSuccessor') {
fn.apply( this, arguments );
}
return ret;
}
}
let order = order500.after( order200 ).after( orderNormal );
order(3, true, 500);
三. 总结
优点:1. 解耦了请求的发送者和 N 哥接收者之间的 复杂关系
2. 每个对象可有灵活拆分,控制请求的入口和长度
缺点: 1. 可能某次传递中大部分节点都只是作为传递,并没有多大的用处,造成性能损耗
无论是作用域链,原型链,还是冒泡事件中都合适的应用了职责链模式。职责链模式还可以和组合模式结合在一起,用来连接部件和父部件,或者提高组合对象的效率。