职责链模式核心概念

  1. 职责链模式 (Chain of Responsibility)
    1. 把多个处理请求的对象连成一条 “链”,请求沿着这条链传递,直到有一个对象能处理它为止;
    2. 核心优势:
      • 解耦:请求发送者和处理者分离,发送者不用知道谁最终处理请求;
      • 灵活:可以动态增删 / 调整链中的处理节点;
  2. 类图:
  3. 实现代码:
    // 1. 定义请求类
    class LeaveRequest {
        constructor(
            public employee: string,      // 员工姓名
            public days: number,          // 请假天数
            public reason: string         // 请假原因
        ) {}
        
        toString(): string {
            return `【${this.employee}】申请请假 ${this.days} 天,原因:${this.reason}`;
        }
    }
    
    // 2. 抽象处理者
    abstract class Approver {
        protected successor: Approver | null = null;
        protected name: string;
        protected position: string;
        
        constructor(name: string, position: string) {
            this.name = name;
            this.position = position;
        }
        
        // 设置下一个审批人
        setSuccessor(successor: Approver): void {
            this.successor = successor;
        }
        
        // 抽象审批方法
        abstract handleRequest(request: LeaveRequest): void;
        
        // 传递给下一个审批人
        protected passToNext(request: LeaveRequest): void {
            if (this.successor) {
                console.log(`📤 ${this.position} ${this.name} 无法审批,转交给下一级...`);
                this.successor.handleRequest(request);
            } else {
                console.log(`❌ 无人能够审批该请求,需特殊处理!`);
            }
        }
    }
    
    // 3. 具体处理者:组长
    class TeamLeader extends Approver {
        constructor(name: string) {
            super(name, '组长');
        }
        
        handleRequest(request: LeaveRequest): void {
            if (request.days <= 1) {
                console.log(`✅ [${this.position} ${this.name}] 已批准:${request}`);
                console.log(`   💬 组长:好好休息,注意身体!`);
            } else {
                this.passToNext(request);
            }
        }
    }
    
    // 4. 具体处理者:部门经理
    class DepartmentManager extends Approver {
        constructor(name: string) {
            super(name, '部门经理');
        }
        
        handleRequest(request: LeaveRequest): void {
            if (request.days <= 3) {
                console.log(`✅ [${this.position} ${this.name}] 已批准:${request}`);
                console.log(`   💬 经理:请安排好工作交接。`);
            } else {
                this.passToNext(request);
            }
        }
    }
    
    // 5. 具体处理者:人力资源总监
    class HRDirector extends Approver {
        constructor(name: string) {
            super(name, 'HR总监');
        }
        
        handleRequest(request: LeaveRequest): void {
            if (request.days <= 7) {
                console.log(`✅ [${this.position} ${this.name}] 已批准:${request}`);
                console.log(`   💬 HR总监:记得按时回来销假。`);
            } else {
                this.passToNext(request);
            }
        }
    }
    
    // 6. 具体处理者:总经理
    class GeneralManager extends Approver {
        constructor(name: string) {
            super(name, '总经理');
        }
        
        handleRequest(request: LeaveRequest): void {
            if (request.days <= 30) {
                console.log(`✅ [${this.position} ${this.name}] 已批准:${request}`);
                console.log(`   💬 总经理:准假,注意工作交接。`);
            } else {
                this.passToNext(request);
            }
        }
    }
    
    // 7. 客户端代码
    class Company {
        private approverChain: Approver;
        
        constructor() {
            // 创建审批人
            const teamLeader = new TeamLeader('张三');
            const departmentManager = new DepartmentManager('李四');
            const hrDirector = new HRDirector('王五');
            const generalManager = new GeneralManager('赵六');
            
            // 构建职责链
            teamLeader.setSuccessor(departmentManager);
            departmentManager.setSuccessor(hrDirector);
            hrDirector.setSuccessor(generalManager);
            
            this.approverChain = teamLeader;
            
            console.log('🏢 公司请假审批系统已初始化');
            console.log('审批链:组长 → 部门经理 → HR总监 → 总经理\n');
        }
        
        submitLeaveRequest(employee: string, days: number, reason: string): void {
            const request = new LeaveRequest(employee, days, reason);
            console.log(`\n📋 收到请假申请:${request}`);
            console.log('开始审批流程...');
            this.approverChain.handleRequest(request);
            console.log('审批流程结束。');
        }
    }
    
    // 8. 测试代码
    const company = new Company();
    
    // 测试不同天数的请假
    console.log('='.repeat(50));
    company.submitLeaveRequest('小明', 0.5, '身体不适');
    
    console.log('='.repeat(50));
    company.submitLeaveRequest('小红', 2, '家里有事');
    
    console.log('='.repeat(50));
    company.submitLeaveRequest('小张', 5, '婚礼');
    
    console.log('='.repeat(50));
    company.submitLeaveRequest('小李', 15, '带父母出国旅游');
    
    console.log('='.repeat(50));
    company.submitLeaveRequest('小王', 40, '长期进修');
    

常用使用场景

表单校验(前端最经典场景)

  1. 表单提交前需要依次校验:「非空校验 → 手机号格式校验 → 验证码长度校验」,任一环节失败则终止校验并提示,全部通过则校验成功;

  2. 实现代码:

    /**
     * 抽象校验处理器
     */
    abstract class FormValidatorHandler {
      protected nextHandler: FormValidatorHandler | null = null;
    
      setNext(handler: FormValidatorHandler): FormValidatorHandler {
        this.nextHandler = handler;
        return handler;
      }
    
      abstract validate(fieldName: string, value: any): { pass: boolean; msg: string };
    }
    
    /**
     * 非空校验处理器
     */
    class RequiredValidator extends FormValidatorHandler {
      validate(fieldName: string, value: any): { pass: boolean; msg: string } {
        if (value === '' || value === undefined || value === null) {
          return { pass: false, msg: `${fieldName}不能为空` };
        }
        // 非空则传给下一个处理器
        if (this.nextHandler) {
          return this.nextHandler.validate(fieldName, value);
        }
        return { pass: true, msg: '校验通过' };
      }
    }
    
    /**
     * 手机号格式校验处理器
     */
    class PhoneValidator extends FormValidatorHandler {
      validate(fieldName: string, value: any): { pass: boolean; msg: string } {
        const phoneReg = /^1[3-9]\d{9}$/;
        if (!phoneReg.test(value)) {
          return { pass: false, msg: `${fieldName}格式不正确` };
        }
        if (this.nextHandler) {
          return this.nextHandler.validate(fieldName, value);
        }
        return { pass: true, msg: '校验通过' };
      }
    }
    
    /**
     * 验证码长度校验处理器
     */
    class CodeValidator extends FormValidatorHandler {
      validate(fieldName: string, value: any): { pass: boolean; msg: string } {
        if (value.length !== 6) {
          return { pass: false, msg: `${fieldName}必须是6位数字` };
        }
        return { pass: true, msg: '校验通过' };
      }
    }
    
    // 测试代码
    console.log('===== 表单校验测试 =====');
    // 1. 创建校验器链:非空 → 手机号 → 验证码
    const required = new RequiredValidator();
    const phone = new PhoneValidator();
    const code = new CodeValidator();
    required.setNext(phone).setNext(code);
    
    // 2. 测试不同场景
    console.log('场景1:手机号为空', required.validate('手机号', ''));
    console.log('场景2:手机号格式错误', required.validate('手机号', '1234567890'));
    console.log('场景3:验证码长度错误', required.validate('验证码', '12345'));
    console.log('场景4:全部校验通过', required.validate('验证码', '123456'));
    

权限校验(前端权限控制)

  1. 用户操作按钮前的权限校验链:「登录状态校验 → 角色权限校验 → 操作范围校验」,任一环节失败则禁止操作,全部通过则允许操作;

  2. 实现代码:

    /**
     * 抽象权限处理器
     */
    abstract class PermissionHandler {
      protected nextHandler: PermissionHandler | null = null;
    
      setNext(handler: PermissionHandler): PermissionHandler {
        this.nextHandler = handler;
        return handler;
      }
    
      abstract check(userId: string, action: string): { allow: boolean; reason: string };
    }
    
    /**
     * 登录状态校验
     */
    class LoginPermissionHandler extends PermissionHandler {
      // 模拟已登录用户列表
      private loggedUsers = ['user001', 'user002'];
    
      check(userId: string, action: string): { allow: boolean; reason: string } {
        if (!this.loggedUsers.includes(userId)) {
          return { allow: false, reason: '未登录,禁止操作' };
        }
        return this.nextHandler ? this.nextHandler.check(userId, action) : { allow: true, reason: '权限通过' };
      }
    }
    
    /**
     * 角色权限校验
     */
    class RolePermissionHandler extends PermissionHandler {
      // 模拟角色权限:admin可操作所有,editor只能编辑,viewer只能查看
      private rolePermissions = {
        user001: 'admin',
        user002: 'editor',
        user003: 'viewer'
      };
    
      check(userId: string, action: string): { allow: boolean; reason: string } {
        const role = this.rolePermissions[userId];
        if (role === 'admin') {
          return this.nextHandler ? this.nextHandler.check(userId, action) : { allow: true, reason: '权限通过' };
        }
        if (role === 'editor' && action !== 'delete') {
          return this.nextHandler ? this.nextHandler.check(userId, action) : { allow: true, reason: '权限通过' };
        }
        if (role === 'viewer' && action === 'view') {
          return this.nextHandler ? this.nextHandler.check(userId, action) : { allow: true, reason: '权限通过' };
        }
        return { allow: false, reason: `角色${role}无${action}权限` };
      }
    }
    
    /**
     * 操作范围校验
     */
    class ScopePermissionHandler extends PermissionHandler {
      // 模拟操作范围:user001可操作所有部门,user002只能操作自己部门(部门A)
      private scopePermissions = {
        user001: ['部门A', '部门B', '部门C'],
        user002: ['部门A']
      };
    
      check(userId: string, action: string): { allow: boolean; reason: string } {
        // 假设action格式为:操作_部门,如delete_部门B
        const [_, dept] = action.split('_');
        if (!dept) {
          return { allow: true, reason: '权限通过' };
        }
        const scopes = this.scopePermissions[userId];
        if (scopes && scopes.includes(dept)) {
          return { allow: true, reason: '权限通过' };
        }
        return { allow: false, reason: `无${dept}的操作权限` };
      }
    }
    
    // 测试代码
    console.log('\n===== 权限校验测试 =====');
    // 1. 构建权限链:登录 → 角色 → 操作范围
    const loginHandler = new LoginPermissionHandler();
    const roleHandler = new RolePermissionHandler();
    const scopeHandler = new ScopePermissionHandler();
    loginHandler.setNext(roleHandler).setNext(scopeHandler);
    
    // 2. 测试不同场景
    console.log('场景1:未登录用户操作', loginHandler.check('user003', 'delete'));
    console.log('场景2:编辑者删除操作', loginHandler.check('user002', 'delete'));
    console.log('场景3:编辑者操作其他部门', loginHandler.check('user002', 'edit_部门B'));
    console.log('场景4:管理员操作所有部门', loginHandler.check('user001', 'delete_部门C'));
    

请求重试 / 降级(前端容错处理)

  1. 接口请求失败后的容错处理链:「重试 2 次 → 切换备用接口 → 展示降级提示」,依次执行,直到处理成功或全部失败;

  2. 实现代码:

    /**
     * 抽象请求处理器
     */
    abstract class RequestHandler {
      protected nextHandler: RequestHandler | null = null;
    
      setNext(handler: RequestHandler): RequestHandler {
        this.nextHandler = handler;
        return handler;
      }
    
      abstract handle(url: string, params: any): Promise<{ success: boolean; data: any; msg: string }>;
    }
    
    /**
     * 重试处理器
     */
    class RetryRequestHandler extends RequestHandler {
      private retryCount = 0;
      private maxRetry = 2; // 最大重试次数
    
      async handle(url: string, params: any): Promise<{ success: boolean; data: any; msg: string }> {
        try {
          // 模拟请求(第一次失败,重试后成功)
          const response = await this.mockRequest(url, params);
          return { success: true, data: response, msg: '请求成功' };
        } catch (error) {
          this.retryCount++;
          if (this.retryCount <= this.maxRetry) {
            console.log(`请求失败,第${this.retryCount}次重试`);
            return this.handle(url, params); // 重试
          }
          // 重试次数用完,传给下一个处理器
          if (this.nextHandler) {
            return this.nextHandler.handle(url, params);
          }
          return { success: false, data: null, msg: '重试失败' };
        }
      }
    
      // 模拟请求(模拟前2次失败,第3次成功)
      private async mockRequest(url: string, params: any): Promise<any> {
        return new Promise((resolve, reject) => {
          setTimeout(() => {
            if (this.retryCount < this.maxRetry) {
              reject(new Error('请求超时'));
            } else {
              resolve({ code: 200, data: { id: 1 } });
            }
          }, 500);
        });
      }
    }
    
    /**
     * 备用接口处理器
     */
    class BackupRequestHandler extends RequestHandler {
      async handle(url: string, params: any): Promise<{ success: boolean; data: any; msg: string }> {
        try {
          // 模拟备用接口请求
          const backupUrl = `/backup${url}`;
          console.log(`切换到备用接口:${backupUrl}`);
          const response = await this.mockBackupRequest(backupUrl, params);
          return { success: true, data: response, msg: '备用接口请求成功' };
        } catch (error) {
          if (this.nextHandler) {
            return this.nextHandler.handle(url, params);
          }
          return { success: false, data: null, msg: '备用接口请求失败' };
        }
      }
    
      private async mockBackupRequest(url: string, params: any): Promise<any> {
        return new Promise((resolve) => {
          setTimeout(() => {
            resolve({ code: 200, data: { id: 1, backup: true } });
          }, 500);
        });
      }
    }
    
    /**
     * 降级处理处理器
     */
    class FallbackRequestHandler extends RequestHandler {
      async handle(url: string, params: any): Promise<{ success: boolean; data: any; msg: string }> {
        console.log('接口全部失败,展示降级数据');
        // 返回降级数据
        return {
          success: false,
          data: { id: 0, fallback: true, content: '暂无数据,请稍后重试' },
          msg: '已展示降级提示'
        };
      }
    }
    
    // 测试代码
    console.log('\n===== 请求重试/降级测试 =====');
    // 1. 构建请求处理链:重试 → 备用接口 → 降级
    const retryHandler = new RetryRequestHandler();
    const backupHandler = new BackupRequestHandler();
    const fallbackHandler = new FallbackRequestHandler();
    retryHandler.setNext(backupHandler).setNext(fallbackHandler);
    
    // 2. 测试请求(这里修改maxRetry为3可以测试备用接口,为4测试降级)
    retryHandler.handle('/api/user', { id: 1 }).then(res => {
      console.log('最终结果:', res);
    });
    

职责链模式的优缺点

  1. 优点:

    1. 解耦:请求发送者和接收者解耦;
    2. 灵活性高:可以动态改变链内成员或调整顺序;
    3. 符合开闭原则:增加新的处理者无需修改现有代码;
    4. 责任单一:每个类只处理自己负责的请求;
  2. 缺点:

    1. 请求可能不被处理:链末端没有处理者时,请求可能被忽略;
    2. 性能影响:链较长时可能影响性能;
    3. 调试困难:递归式的调用使调试变得复杂;
    4. 可能导致循环引用:如果链设置不当可能形成环;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 职责链模式核心概念
  2. 2. 常用使用场景
    1. 2.1. 表单校验(前端最经典场景)
    2. 2.2. 权限校验(前端权限控制)
    3. 2.3. 请求重试 / 降级(前端容错处理)
  3. 3. 职责链模式的优缺点