职责链模式

用请假审批场景理解职责链模式的实现

问题

用职责链模式实现一个请假审批系统:

  • 请假 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 事件冒泡、审批流程
  • 注意:链太长会影响性能,需要保证链有终点避免死循环