职责链模式核心概念
- 职责链模式 (Chain of Responsibility):
- 把多个处理请求的对象连成一条 “链”,请求沿着这条链传递,直到有一个对象能处理它为止;
- 核心优势:
- 解耦:请求发送者和处理者分离,发送者不用知道谁最终处理请求;
- 灵活:可以动态增删 / 调整链中的处理节点;
- 类图:
- 实现代码:
// 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, '长期进修');
常用使用场景
表单校验(前端最经典场景)
-
表单提交前需要依次校验:「非空校验 → 手机号格式校验 → 验证码长度校验」,任一环节失败则终止校验并提示,全部通过则校验成功;
-
实现代码:
/** * 抽象校验处理器 */ 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'));
权限校验(前端权限控制)
-
用户操作按钮前的权限校验链:「登录状态校验 → 角色权限校验 → 操作范围校验」,任一环节失败则禁止操作,全部通过则允许操作;
-
实现代码:
/** * 抽象权限处理器 */ 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'));
请求重试 / 降级(前端容错处理)
-
接口请求失败后的容错处理链:「重试 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); });
职责链模式的优缺点
-
优点:
- 解耦:请求发送者和接收者解耦;
- 灵活性高:可以动态改变链内成员或调整顺序;
- 符合开闭原则:增加新的处理者无需修改现有代码;
- 责任单一:每个类只处理自己负责的请求;
-
缺点:
- 请求可能不被处理:链末端没有处理者时,请求可能被忽略;
- 性能影响:链较长时可能影响性能;
- 调试困难:递归式的调用使调试变得复杂;
- 可能导致循环引用:如果链设置不当可能形成环;
模版方法模式(行为型模式)
上一篇