职责链模式
用请假审批场景理解职责链模式的实现
问题
用职责链模式实现一个请假审批系统:
- 请假 1 天内:组长审批
- 请假 3 天内:经理审批
- 请假 7 天内:总监审批
- 请假超过 7 天:老板审批
解答
基本实现
// 处理者基类
class Handler {
constructor(name) {
this.name = name;
this.nextHandler = null;
}
// 设置下一个处理者
setNext(handler) {
this.nextHandler = handler;
return handler; // 返回 handler 方便链式调用
}
// 处理请求(子类重写)
handle(days) {
if (this.nextHandler) {
return this.nextHandler.handle(days);
}
return `${days} 天假期无人能批`;
}
}
// 组长:1 天内
class TeamLeader extends Handler {
handle(days) {
if (days <= 1) {
return `${this.name} 批准了 ${days} 天假期`;
}
return super.handle(days);
}
}
// 经理:3 天内
class Manager extends Handler {
handle(days) {
if (days <= 3) {
return `${this.name} 批准了 ${days} 天假期`;
}
return super.handle(days);
}
}
// 总监:7 天内
class Director extends Handler {
handle(days) {
if (days <= 7) {
return `${this.name} 批准了 ${days} 天假期`;
}
return super.handle(days);
}
}
// 老板:7 天以上
class Boss extends Handler {
handle(days) {
return `${this.name} 批准了 ${days} 天假期`;
}
}
// 构建职责链
const leader = new TeamLeader('组长');
const manager = new Manager('经理');
const director = new Director('总监');
const boss = new Boss('老板');
leader.setNext(manager).setNext(director).setNext(boss);
// 测试
console.log(leader.handle(0.5)); // 组长批准了 0.5 天假期
console.log(leader.handle(2)); // 经理批准了 2 天假期
console.log(leader.handle(5)); // 总监批准了 5 天假期
console.log(leader.handle(10)); // 老板批准了 10 天假期
函数式实现
// 创建处理者
const createHandler = (name, maxDays, next) => (days) => {
if (days <= maxDays) {
return `${name} 批准了 ${days} 天假期`;
}
return next ? next(days) : `${days} 天假期无人能批`;
};
// 从后往前构建链
const boss = createHandler('老板', Infinity, null);
const director = createHandler('总监', 7, boss);
const manager = createHandler('经理', 3, director);
const leader = createHandler('组长', 1, manager);
// 测试
console.log(leader(0.5)); // 组长批准了 0.5 天假期
console.log(leader(2)); // 经理批准了 2 天假期
console.log(leader(5)); // 总监批准了 5 天假期
console.log(leader(10)); // 老板批准了 10 天假期
实际应用:表单验证
// 验证规则链
const validators = [
{
validate: (value) => value !== '',
message: '不能为空'
},
{
validate: (value) => value.length >= 6,
message: '长度至少 6 位'
},
{
validate: (value) => /\d/.test(value),
message: '必须包含数字'
}
];
// 执行验证链
function validate(value, rules) {
for (const rule of rules) {
if (!rule.validate(value)) {
return { valid: false, message: rule.message };
}
}
return { valid: true };
}
console.log(validate('', validators)); // { valid: false, message: '不能为空' }
console.log(validate('abc', validators)); // { valid: false, message: '长度至少 6 位' }
console.log(validate('abcdef', validators)); // { valid: false, message: '必须包含数字' }
console.log(validate('abc123', validators)); // { valid: true }
关键点
- 解耦:请求发送者不需要知道谁来处理,只需把请求交给链的第一个节点
- 灵活:可以动态增删处理者,调整处理顺序
- 单一职责:每个处理者只关心自己能处理的情况
- 常见场景:表单验证、中间件(Express/Koa)、DOM 事件冒泡、审批流程
- 注意:链太长会影响性能,需要保证链有终点避免死循环
目录