js设计模式-职责链模式

发布于:2025-09-04 ⋅ 阅读:(23) ⋅ 点赞:(0)

一. 概览

定义:目的是将请求发送者与接受者解耦,请求会沿着一条链传递,直到有对象处理它。
角色: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' 
    

三.核心知识点

链式构建过程分析:

  1. 第一步赋值
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. 语法调用的是父类的方法,但方法内部使用的是子类实例的当前属性值

五. 总结

优点

  1. 解耦请求与处理者:发送者无需知道具体处理者是谁。
  2. 动态配置链:可以在运行时动态调整链中的处理顺序或增减节点。
  3. 扩展灵活:新增处理者不影响现有链,只需实现handleRequest和插入链中。

适用场景
1.多对象可能处理同一个请求。
2.处理顺序需要动态调整。
4. 需隐藏接收者,由链决定传递路径。
比如:
日志分级
DEBUG → INFO → WARNING → ERROR 不同级别由对应处理器过滤。
权限验证
用户请求逐层验证角色、组织、ID权限。
命令调度
接收器将未识别的指令传递给下一个可用处理器。