JavaScript 设计模式:责任链模式的原理与实战应用

江岸
江岸
发布时间:2026-10-14| 5人浏览过
原创

责任链模式是 JavaScript 中用于解耦请求发送者与处理者的常用设计模式。通过将多个处理对象连成一条链,请求沿着链传递直至被处理。本文结合电商订单优惠规则与浏览器文件上传兼容性问题,详细演示如何实现该模式,并探讨其在现代前端开发中的应用价值。

什么是责任链模式

责任链模式(Chain of Responsibility)的核心目标是解耦。它使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。这些对象被连接成一条链,请求沿着这条链传递,直到链上的某一个对象处理它为止。

在传统编程中,我们常使用大量 if-else 或 switch 语句来处理不同条件分支。随着业务逻辑增加,这样的结构会变得难以维护。责任链模式提供了一种将每个条件封装为独立节点的方法,每个节点只关注自己是否处理该请求,若不能处理则传递给下一个节点。

示例一:电商订单优惠逻辑重构

假设我们正在开发一个售卖手机的电商网站,针对预定用户实行不同的优惠策略:

  • 500元定金用户:若已支付定金,获得100元优惠券;否则按普通购买处理。
  • 200元定金用户:若已支付定金,获得50元优惠券;否则按普通购买处理。
  • 普通购买用户:无优惠券,但在有库存的情况下可保证买到。

第1步:分析传统实现的弊端

在传统的命令式写法中,我们需要嵌套多层判断逻辑。以下代码展示了未使用设计模式时的典型实现方式:

var order = function(orderType, isPaid, stock) {
  if(orderType === 1) { // 500定金
    if(isPaid) {
      console.log("500元定金预购,得到100优惠券");
    } else {
      if(stock > 0) {
        console.log("普通购买,无优惠券");
      } else {
        console.log("库存不足");
      }
    }
  } else if(orderType === 2) { // 200定金
    if(isPaid) {
      console.log("200元定金预购,得到50优惠券");
    } else {
      if(stock > 0) {
        console.log("普通购买,无优惠券");
      } else {
        console.log("库存不足");
      }
    }
  } else if(orderType === 3) { // 普通购买
    if(stock > 0) {
      console.log("普通购买,无优惠券");
    } else {
      console.log("库存不足");
    }
  }
}

问题指出:
1. 冗余代码多:“普通购买”和“库存不足”的逻辑在多个分支中重复出现。
2. 耦合度高:新增一种定金类型(如1000元)需要修改现有函数内部逻辑,违反开闭原则。
3. 可读性差:深层嵌套使核心业务逻辑难以快速理解。

第2步:构建责任链节点

我们可以将每种情况封装为一个独立的函数,每个函数只判断自己是否满足条件。如果满足则处理,如果不满足则返回一个特殊标记 "nextSuccessor",表示将请求交给下一个节点。

// 处理500定金订单
var order500 = function(orderType, isPaid, stock) {
  if(orderType === 1 && isPaid === true) {
    console.log("500元定金预购,得到100优惠券");
  } else {
    return "nextSuccessor";
  }
};

// 处理200定金订单
var order200 = function(orderType, isPaid, stock) {
  if(orderType === 2 && isPaid === true) {
    console.log("200元定金预购,得到50优惠券");
  } else {
    return "nextSuccessor";
  }
};

// 处理普通订单及库存检查
var orderNormal = function(orderType, isPaid, stock) {
  if(stock > 0) {
    console.log("普通购买,无优惠券");
  } else {
    console.log("库存不足");
  }
};

第3步:实现链条连接机制

为了让第一个函数的返回值能自动触发第二个函数,我们需要扩展 JavaScript 的 Function.prototype,添加一个 after 方法。该方法返回一个新的函数,用于串联处理逻辑。

Function.prototype.after = function(fn) {
  var self = this;
  return function() {
    var ret = self.apply(this, arguments);
    if(ret === "nextSuccessor") {
      return fn.apply(this, arguments);
    }
    return ret;
  };
};

逻辑解析:
调用 a.after(b) 时,新函数会先执行 a。如果 a 返回 "nextSuccessor",则继续执行 b;否则直接返回 a 的结果。

第4步:组装并测试责任链

现在可以将所有节点组装成一条链,并通过统一的入口进行调用:

var order = order500.after(order200).after(orderNormal);
order(1, true, 10); // 输出: 500元定金预购,得到100优惠券

优势总结:
- 解耦:发送者无需知道有哪些处理者,也无需关心处理顺序。 - 可扩展:如需新增“1000元定金”逻辑,只需新建一个 order1000 函数,并在链条中插入即可,无需修改原有代码。

示例二:跨浏览器文件上传对象获取

在早期的 Web 开发中,文件上传的方式多种多样(Flash、ActiveX、原生表单)。为了在不同浏览器中统一获取最优上传对象,责任链模式同样适用。

function getActiveUploadObj() {
  try {
    return new ActiveObject("TXFTNActiveX.FTNUpload"); // IE上传控件
  } catch(e) {
    return "nextSuccessor";
  }
}

function getFlashUploadObj() {
  if(supportFlash().f === 1) {
    var str = '';
    return $(str).appendTo($("body"));
  }
  return "nextSuccessor";
}

function getFormUploadObj() {
  var str = '';
  return $(str).appendTo($("body"));
}

var getUploadObj = getActiveUploadObj.after(getFlashUploadObj).after(getFormUploadObj);
console.log(getUploadObj());

执行流程:
1. 优先尝试通过 ActiveX 获取 IE 专属对象。
2. 若失败,尝试检测 Flash 并生成 Flash 对象。
3. 若 Flash 不可用,最终降级使用原生 HTML 表单上传。

优缺点与适用场景

优点

  • 降低耦合度: sender 和 receiver 之间没有直接的引用关系,系统更灵活。
  • 简化对象: 每个类只需要关心自己的业务逻辑,符合单一职责原则。
  • 动态组合: 运行时可以改变链的结构,支持不同的处理方式。

缺点

  • 请求不被保证: 某些请求可能因为没有任何节点处理而没有被处理掉(需确保链尾有兜底逻辑)。
  • 调试困难: 逻辑分散在多个节点中,调试时可能需要跟踪整个链条的传递过程。

适用场景

  • 事件冒泡: DOM 元素的事件传播本身就是典型的责任链。
  • 中间件系统: Koa 等框架的洋葱模型也是基于此模式的思想。
  • 审批流程: 企业 OA 系统中逐级审批的场景。
  • 兼容性处理: 如上文所述的多方案降级处理。

无论是作用域链、原型链还是 DOM 节点中的事件冒泡,我们都能从中找到责任链的影子。合理使用该模式,可以显著提升前端代码的组织结构和可维护性。

以上就是 JavaScript 设计模式中责任链模式的详细内容,更多关于 JavaScript 架构优化的资料请关注本站其它相关文章!

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。