js设计模式-职责链模式
一. 概览
定义:目的是将请求发送者与接受者解耦,请求会沿着一条链传递,直到有对象处理它。
角色:1. 抽象处理者(Handler):定义处理请求的接口,并维护对下一个处理者的引用。
2. 具体处理者(Concrete Handler):实现请求处理逻辑,判断是否处理或传递给下家。
3. 客户端(Client):组装链并触发请求
核心思想:
请求无需直接指定处理者,而是依次传递给链中的每个对象。每个处理者可自行决定是否处理请求(如检查条件或层级),若无法处理,将请求传给链中的下一个处理者。
最后可能返回默认结果(如未处理)。
二. 代码示例
// 抽象处理者
class Handler {constructor() {this.nextHandler = null; // 当前处理者的下一个节点}// 抽象方法:由子类实现具体逻辑handleRequest(request) {if (this.nextHandler) {return this.nextHandler.handleRequest(request);}return `Request '${request}' not handled by any handler.`;}// 设置下一个处理者setNext(handler) {this.nextHandler = handler;return handler; // 支持链式调用}
}// 具体处理者
class DebugHandler extends Handler {handleRequest(request) {debugger;if (request.level === 'DEBUG') {return `DEBUG: ${request.message}`;}// 否则传递给下一个处理者return super.handleRequest(request);}
}// 处理INFO级别的日志
class InfoHandler extends Handler {handleRequest(request) {if (request.level === 'INFO') {return `INFO: ${request.message}`;}return super.handleRequest(request);}
}// 处理ERROR级别的日志
class ErrorHandler extends Handler {debugger;handleRequest(request) {if (request.level === 'ERROR') {return `ERROR: ${request.message}`;}return super.handleRequest(request);}
}// 客户端代码
// 创建各处理者实例
const debugHandler = new DebugHandler();
const infoHandler = new InfoHandler();
const errorHandler = new ErrorHandler();// 构建处理链:DEBUG → INFO → ERROR
debugHandler.setNext(infoHandler).setNext(errorHandler);// 发送不同请求测试链的处理能力
console.log(debugHandler.handleRequest({ level: 'DEBUG', message: 'System initialized' }));
// 输出:DEBUG: System initializedconsole.log(debugHandler.handleRequest({ level: 'INFO', message: 'User signed in' }));
// 输出:INFO: User signed inconsole.log(debugHandler.handleRequest({ level: 'ERROR', message: 'Null reference' }));
// 输出:ERROR: Null referenceconsole.log(debugHandler.handleRequest({ level: 'WARNING', message: 'Disk space low' }));
// 输出:Request 'WARNING'
三.核心知识点
链式构建过程分析:
- 第一步赋值
debugHandler.setNext(infoHandler)
debugHandler 的 nextHandler 被设置为 infoHandler;
返回值是 infoHandler,作为下一步调用的起点
2.第二步赋值(在返回的 infoHandler 上继续)
infoHandler.setNext(errorHandler)
infoHandler 的 nextHandler 被设置为 errorHandler;
最终形成链 debugHandler.nextHandler = infoHandler→ infoHandler.nextHandler = errorHandler → errorHandler.nextHandler = null。
debugHandler.handleRequest({ level: 'WARNING', ... })├─ DebugHandler.check(...) → 不匹配├─ 调用 `super.handleRequest` → 转向 `debugHandler.nextHandler = infoHandler`│└─ InfoHandler.check(...) → 不匹配└─ 调用 `super.handleRequest` → 转向 `infoHandler.nextHandler = errorHandler`│└─ ErrorHandler.check(...) → 不匹配└─ 调用 `super.handleRequest` → 转向 `errorHandler.nextHandler = null`└─ 返回默认错误提示
四. this指向
class makeDrink {constructor() {this.age = 18}handleRequest() {console.log(this.age, 'checkAge')}
}class makeTea extends makeDrink {constructor() {super();this.age = 19}handleRequest() {super.handleRequest();}
}const teaData = new makeTea();
teaData.handleRequest();
为什么打印的是19,super不是继承的父类吗?
原因是:
子类 MakeTea 的构造函数首先通过 super() 调用了父类 MakeDrink 的构造函数
父类构造函数为当前实例(this)设置了 age = 18
子类构造函数在父类初始化完成后,通过 this.age = 19 覆盖了父类设置的属性值
当调用 super.handleRequest() 时:
this 指针仍然指向子类实例
访问的是当前实例的 age 属性(已经被子类修改为19)
关键点:
JavaScript 的继承机制中:
子类实例的属性是直接存储在该实例本身(而不是父类实例)
子类可以覆盖父类在构造函数中设置的属性
super. 语法调用的是父类的方法,但方法内部使用的是子类实例的当前属性值
五. 总结
优点
- 解耦请求与处理者:发送者无需知道具体处理者是谁。
- 动态配置链:可以在运行时动态调整链中的处理顺序或增减节点。
- 扩展灵活:新增处理者不影响现有链,只需实现handleRequest和插入链中。
适用场景
1.多对象可能处理同一个请求。
2.处理顺序需要动态调整。
4. 需隐藏接收者,由链决定传递路径。
比如:
日志分级
DEBUG → INFO → WARNING → ERROR 不同级别由对应处理器过滤。
权限验证
用户请求逐层验证角色、组织、ID权限。
命令调度
接收器将未识别的指令传递给下一个可用处理器。