职责链模式
职责链模式指的是使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
概念
节点:一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇到一个可以处理它的对象,我们把这些对象称为链中的节点
职责链的结构
职责链由一个个节点构成,每个节点都是一个对象,对象中都包含相同的属性名和方法名,这样就容易添加、删除节点。
构造函数,用来构造链中的节点,每个节点都保存处理函数,记录下一个节点。
function Chain (fn){
this.fn = fn;
this.successor = null;
}
设置当前节点的下一个处理的节点,与其他节点建立链接,从而形成链式结构
Chain.prototype.setSuccessor = function (successor){
this.successor = successor;
}
执行处理函数,根据处理结果判断是否需要继续执行。
// 传递请求给某个节点。统一规定当函数返回nextSuccessor时将请求传递给下一个函数
Chain.prototype.passRequest = function (){
let ret = this.fn.apply(this, arguments);
if(ret === 'nextSuccessor'){
this.successor && this.successor.passRequest.apply(this.successor, arguments);
}
return ret;
}
示例:订购手机
如果用户预付定金500元,则获得100元优惠。如果用户预付定金200元,则获得50元优惠。如果不预付定金,当库存不足的时候得不到手机,当库存足够的时候可以得到手机。
// 预付定金500的处理函数
function order500(orderType, pay, stock){
if(orderType === 1 && pay){
console.log('500元定金已付,获得100元优惠券');
} else {
return 'nextSuccessor';
}
}
// 预付定金200的处理函数
function order200(orderType, pay, stock){
if(orderType === 2 && pay){
console.log('200元定金已付,获得50元优惠券');
} else {
return 'nextSuccessor';
}
}
// 不预付定金的处理函数
function orderNormal(orderType, pay, stock){
if(stock > 0){
console.log('普通购买,暂无优惠券');
} else {
console.log('手机库存不足');
}
}
// 构造函数,用来构造链中的节点
function Chain (fn){
this.fn = fn; // 当前处理的节点
this.successor = null; // 下一个处理的节点
}
// 设置下一个处理的节点
Chain.prototype.setSuccessor = function (successor){
this.successor = successor;
}
// 传递请求给某个节点。统一规定当函数返回nextSuccessor时将请求传递给下一个函数
Chain.prototype.passRequest = function (){
let ret = this.fn.apply(this, arguments);
if(ret === 'nextSuccessor'){
this.successor && this.successor.passRequest.apply(this.successor, arguments);
}
return ret;
}
let chain500 = new Chain(order500);
let chain200 = new Chain(order200);
let chainNormal = new Chain(orderNormal);
chain500.setSuccessor(chain200);
chain200.setSuccessor(chainNormal);
chain500.passRequest(1, true, 500);
chain500.passRequest(2, true, 500);
chain500.passRequest(0, true, 1);
示例:异步职责链
// 构造函数,用来构造链中的节点
function Chain(fn) {
this.fn = fn;
this.successor = null;
}
// 设置下一个节点
Chain.prototype.setSuccessor = function (successor) {
this.successor = successor;
}
// 处理请求
Chain.prototype.passRequest = function () {
let ret = this.fn.apply(this, arguments);
}
// 传递请求到下一个节点
Chain.prototype.next = function () {
this.successor && this.successor.fn.apply(this.successor, arguments);
}
function payment() {
setTimeout(() => {
console.log('第一阶段完成');
this.next();
}, 2000);
}
function unionPay() {
setTimeout(() => {
console.log('第二阶段完成');
this.next();
}, 2000);
}
function request() {
setTimeout(() => {
console.log('第三阶段完成');
}, 2000);
}
let chainPayment = new Chain(payment);
let chainUnionPay = new Chain(unionPay);
let chainRequest = new Chain(request);
chainPayment.setSuccessor(chainUnionPay);
chainUnionPay.setSuccessor(chainRequest);
chainPayment.passRequest();
职责链模式的优缺点
优点
- 解耦了请求者和多个接收者之间的复杂关系,只需要把请求发给第一个节点即可,不必关心被谁处理
- 可以灵活地添加链中的节点和设置节点的顺序
- 可以手动指定起始节点,节点并不是一定从第一个节点开始
缺点
- 不能保证某个的请求一定会被链中的节点处理
- 当链较长时会造成性能损耗
职责链模式的应用场景
职责链模式适用于对同一请求多重处理的情况,例如:对于请求处理,不同的状态使用不同的处理逻辑,只需要交给第一个处理对象,然后就会自动传递处理。
总结
职责链模式可以很好地帮助我们管理代码,降低发起请求的对象和处理请求的对象之间的耦合性。职责链中的节点数量和顺序是可以自由变化的,我们可以在运行时决定链中包含哪些节点
无论是作用域链、原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链模式的影子