这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战
介绍
我们本期将跟大家聊聊职责链模式,它在程序设计里可是老玩家了,无论是作用域链、原型链,还是DOM节点中的事件冒泡,我们都能从中找到职责链模式的影子。表述出来就是,如果发出一个请求,当一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
在生活也有很多栗子比如击鼓传花,或者我们具体举个栗子,比如说,我们想出去旅游,但是软妹币决定了我们能去哪儿,就有了这么一个思考过程,如果软妹币大于3w那么我们就出国旅游,如果小于3w大于1w那就国内游,如果小于1w大于2k,那么就省内游,再往下大于500就近郊,如果连500块都没有,那就回家打游戏行了。可以看出来,我们的旅游计划方案的思考赖于钱的多少形成了一个链条,当条件不满足就往下找一个匹配的方案,就继续往下找满足的方案。
概念
职责链模式是一种行为型模式,它为了使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
案例
我们刚刚说了旅游方案的栗子,就来实现一下,如果按照我们之前的思路就会写一堆if-else做区间判断,下次追加方案或者修改区间的话,无疑是个噩梦。现在我们就用职责链模式来完成一下。
var Chain = function(fn) {
this.fn = fn
this.successor = null;
};
Chain.prototype.setNextSuccessor = function(successor) {
return this.successor = successor;
}
Chain.prototype.passRequest = function() {
this.args = arguments;
var ret = this.fn.apply(this, this.args);
if(ret === 'nextSuccessor') {
return this.next();
}
return ret;
}
Chain.prototype.next = function(){
return this.successor && this.successor.passRequest.apply(this.successor, this.args);
}
我们这里写了一个Chain构造函数,通过setNextSuccessor方法可以设置下一个事件,passRequest方法则是执行当前事件,如果不满足则返回字符串nextSuccessor,然后执行下一个事件。
var planA = function(money) {
if(money >= 30000) return "执行出国旅游";
else return "nextSuccessor";
}
var planB = function(money) {
if(money >= 10000) return "执行国内旅游";
else return "nextSuccessor";
}
var planC = function(money) {
if(money >= 2000) return "执行省内旅游";
else return "nextSuccessor";
}
var planD = function(money) {
if(money >= 500) return "执行近郊游"
else return "nextSuccessor";
}
var planE = function() {
return "在家打游戏不香么"
}
var chainPlanA = new Chain(planA);
var chainPlanB = new Chain(planB);
var chainPlanC = new Chain(planC);
var chainPlanD = new Chain(planD);
var chainPlanE = new Chain(planE);
chainPlanA
.setNextSuccessor(chainPlanB)
.setNextSuccessor(chainPlanC)
.setNextSuccessor(chainPlanD)
.setNextSuccessor(chainPlanE);
这里把我们刚才栗子里说的旅游方案,按照规划一个个的串联起来。接下来,我们就测试一下。
let money = 0;
money = 50000;
console.log("预算为" + money + "元",chainPlanA.passRequest(money))
console.log('--------------------')
money = 800;
console.log("预算为" + money + "元",chainPlanA.passRequest(money))
console.log('--------------------')
money = 10;
console.log("预算为" + money + "元",chainPlanA.passRequest(money))
看完全符合期望,而且我们后面修改起来也是异常的清晰便捷。
优点
- 耦合度降低。
- 对象得到简化。
- 追加或修改逻辑的灵活性增加。
缺点
- 调试难度增加。
- 有死循环的危险。
- 不能保证请求一定被接收。
结语
通过刚才的讲述,我们就会明白了职责链模式它是为了避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。学会了使用它,相信在以后的代码编写过程中,将会对你大有好处。