一. 概览
定义:目的是将请求发送者与接受者解耦,请求会沿着一条链传递,直到有对象处理它。
角色: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 initialized
console.log(debugHandler.handleRequest({ level: 'INFO', message: 'User signed in' }));
// 输出:INFO: User signed in
console.log(debugHandler.handleRequest({ level: 'ERROR', message: 'Null reference' }));
// 输出:ERROR: Null reference
console.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权限。
命令调度
接收器将未识别的指令传递给下一个可用处理器。