设计模式——职责链模式
职责链模式将多个有机会处理请求的对象串联起来,将请求者和接受者解耦并将请求从链的入口传入,直到有一个对象能处理它为止。
实例演示
假设现在有个卖手机的活动,用户来源有3类:
- 预付500定金的可以享受100元优惠。
- 预付200定金的可以享受50元优惠。
- 没有预付不享受优惠。
接收到的参数有订单类型orderType,定金pay,库存stock。我们先用简单的逻辑来实现这个业务功能:
let order = function(orderType, pay, stock) {
if (orderType === 1) {
if (pay === true) {
console.log('得到100元优惠');
} else {
if (stock > 0) {
console.log('无优惠');
} else {
console.log('手机无库存');
}
}
}
else if (orderType === 2) {
if (pay === true) {
console.log('得到50元优惠');
} else {
if (stock > 0) {
console.log('无优惠');
} else {
console.log('手机无库存');
}
}
}
else if (orderType === 3) {
if (stock > 0) {
console.log('无优惠');
} else {
console.log('手机无库存');
}
}
}
职责链模式重构
虽然业务是实现了,但所有的逻辑都耦合在了一起,基本上没有可拓展性。下面用职责链模式重构一下,将3种情况拆分为3个接收节点。
let order500 = function(orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('得到100元优惠');
} else {
order200(orderType, pay, stock); // 传递请求到下一节点
}
};
let order200 = function(orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('得到50元优惠');
} else {
orderNormal(orderType, pay, stock); // 传递请求到下一节点
}
};
let orderNormal = function(orderType, pay, stock) {
if (stock > 0) {
console.log('无优惠');
} else {
console.log('手机无库存');
}
};
可以看到我们成功将不同的节点拆分开来。虽然有了进步,但传递的方式还是耦合在了业务中。如果以后要更改传递方法,就必须深入业务内部去修改。我们可以进一步优化。首先我们约定如果某个节点不能处理请求则返回一个标记字符串next表示需要传递请求。
let order500 = function(orderType, pay, stock) {
if (orderType === 1 && pay === true) {
console.log('得到100元优惠');
} else {
return 'next';
}
};
let order200 = function(orderType, pay, stock) {
if (orderType === 2 && pay === true) {
console.log('得到50元优惠');
} else {
return 'next';
}
};
let orderNormal = function(orderType, pay, stock) {
if (stock > 0) {
console.log('无优惠');
} else {
console.log('无库存');
}
};
接下来我们就这些节点处理函数包装成职责链节点,每个节点应该有下一个节点的数据和传递请求的方法。通过定义构造函数 Chain来进行包装。
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 === 'next') {
return this.successor && this.successor.passRequest.apply(this.successor, arguments);
}
return ret;
};
这样我们就完全解耦了请求者和接受者之间的关系。不需要知道哪个接受者可以处理请求,只要将请求传给这条职责链就可以。
小结
职责链模式虽然降低了耦合性,但使得程序中多了一些节点对象,可能对于大多数请求来说,大部分节点没有起到作用。如果从优化性能的方面考虑,也要注意到请求被不同节点处理的频率并进一步针对处理,以免过长职责链带来性能损耗。
-- EOF --