职责链模式
大约 3 分钟约 976 字
使多个对象都有机会处理请求,从而避免了请求的发送者与多个接收者直接的耦合关系,将这些接收者链接成一条链,顺着这条链传递该请求,直到找到能处理该请求的对象。
在责任链模式中,每个处理对象都包含对下一个处理对象的引用。当一个对象接收到请求后,它会根据条件决定是自己处理这个请求,还是将其传递给链中的下一个对象。这样,请求在链中传递,直到被处理或者整个链都无法处理该请求。
这种模式常用于处理不同种类的请求或在不同条件下需要不同处理的场景,例如不同级别的日志记录器、不同类型的事件处理等。责任链模式可以有效地减少对象间的耦合,并提高系统的灵活性和可扩展性
优缺点
优点
- 降低耦合度:责任链模式让多个对象都有机会处理请求,从而将请求的发送者和接收者解耦。这样,各个处理者只需关注自己的责任范围,无需了解链中其他处理者的细节。
- 增强可扩展性:可以动态地添加或修改处理链。如果需要新增一个处理步骤,只需增加一个新的链节点并适当配置其在链中的位置,而无需修改现有代码。
- 灵活分配责任:可以根据需要在运行时重新组织链或改变成员的责任,使得系统更灵活应对变化。
- 分散请求的处理:责任链模式可以将一个复杂的请求处理过程分散到多个处理者中,使得系统易于管理和维护。
缺点
- 性能问题:每个请求都从链的开始处经过,直到有对象处理它为止。这可能会引入一定的处理延迟,尤其是在链较长的情况下。
- 责任划分不清:如果链中的处理者没有妥善设计,可能会出现某个请求没有被任何处理者处理的情况,或者不明确哪个处理者应当负责处理特定请求。
- 复杂性增加:使用责任链模式可能会使系统结构变得复杂,特别是链中的节点数目较多或者链的结构动态变化时。
实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<input type="text" id="input" />
<button id="btn">注册</button>
<script>
let btn = document.getElementById('btn')
btn.addEventListener('click', () => {
let input = document.getElementById('input')
checks.check()
})
function checkEmpty() {
let input = document.getElementById('input')
if (input.value.length === 0) {
console.log('这里不能为空')
return
}
return 'next'
}
function checkNumber() {
let input = document.getElementById('input')
if (Number.isNaN(+input.value)) {
console.log('这里必须是数字')
return
}
return 'next'
}
function checkLength() {
let input = document.getElementById('input')
if (input.value.length < 6) {
console.log('这里必须大于6个数字')
return
}
return 'next'
}
class Chain {
constructor(fn) {
this.checkRule = fn
this.nextRule = null
}
addRule(nextRule) {
this.nextRule = new Chain(nextRule)
return this.nextRule
}
check() {
this.checkRule() === 'next' ? this.nextRule.check() : null
}
end() {
this.nextRule = {
check: () => 'end',
}
}
}
const checks = new Chain(checkEmpty)
checks
.addRule(checkNumber)
.addRule(checkNumber)
.addRule(checkLength)
.end()
</script>
</body>
</html>
- 优点
- 符合单一职责,使每个方法中都只有一个职责
- 符合开放封闭原则,在需求增加时可以很方便的扩充新的责任
- 使用的时候不需要知道谁才是真正处理方法,减少大量的if或switch语法
- 缺点
- 团队成员需要对责任链存在共识,否则当看到一个方法莫名其妙的返回一个next时一定会很奇怪
- 出错时不好排查问题,因为不知道到底在哪个责任中出的错,需要从链头开始往后找