本文档解释了接口隔离原则(ISP),它是 SOLID 设计原则中的第四个原则,以及如何在 JavaScript 中应用它。虽然 JavaScript 缺乏 Java 或 C# 等语言中的正式接口,但该原则通过 JavaScript 的隐式契约和鸭子类型仍然适用。本页面涵盖了如何识别 ISP 违规、在 JavaScript 中实现接口隔离以及重构代码以更好地遵循该原则。
有关其他 SOLID 原则的信息,请参阅 SOLID 原则、单一职责原则、开闭原则、里氏替换原则 和 依赖倒置原则。
接口隔离原则规定“客户端不应被迫依赖它们不使用的接口。” 本质上,不应强制客户端实现它不需要的方法,或依赖它不使用的方法。
在 JavaScript 中,接口通过对象之间交互的方式是隐式的。当一个对象期望另一个对象具有某些属性或方法时,它们之间就形成了隐式接口。
与静态类型语言不同,JavaScript 没有正式的接口声明。然而,ISP 仍然通过以下方式适用:
肥接口迫使客户端了解并可能实现它们不需要的方法。这会产生几个问题:
README 展示了一个清晰的 ISP 违规示例以及如何使用 DOMTraverser 类来修复它。
糟糕的模式(违反 ISP):在此示例中,即使不需要 animationModule,客户端也被迫提供它。
良好的模式(遵循 ISP):改进后的版本通过将可选功能放入单独的 options 对象中,使可选功能真正可选。
| 技术 | 描述 | 优点 |
|---|---|---|
| 可选参数 | 使参数可选并提供默认值 | 客户端只提供他们需要的东西 |
| 配置对象 | 将相关参数分组到可选对象中 | 减少参数数量,使需求更清晰 |
| 功能检测 | 在使用功能前检查它们 | 允许优雅降级 |
| 组合 | 从简单对象构建复杂对象 | 每个组件都有一个集中的接口 |
方法检查 在尝试使用方法之前检查它们是否存在
可选链 使用可选链进行更简洁的方法检查
默认空对象 提供默认空对象以避免需要检查存在性
README 中的 DOMTraverser 示例展示了如何使用嵌套的配置对象来使接口需求更加灵活。
这种模式在需要处理大量配置选项但又希望其中大部分是可选的 JavaScript 库中很常见。
现代 JavaScript 模块系统通过允许选择性导入来遵循 ISP。
这种模式允许现代打包工具进行“树抖动”,并通过确保消费者只依赖他们实际使用的内容来遵循 ISP。
接口隔离与其他 SOLID 原则紧密合作。
分解大型接口为小型接口
使用可选属性和合理的默认值
实现功能检测
组合优于继承
优先考虑消费者的需求
当遇到 ISP 违规时,应用这些重构策略:
| 违规模式 | 重构策略 |
|---|---|
| 必需但未使用的参数 | 使参数可选并提供默认值 |
| 大型配置对象 | 分解为更小、更集中的对象 |
| 具有许多方法的类 | 分解为更小、可组合的类 |
| 必需的回调函数可能未使用 | 使回调函数可选或使用事件发射器 |
虽然 JavaScript 缺乏正式的接口,但接口隔离原则仍然是设计灵活、可维护代码的宝贵指南。通过确保客户端只依赖他们实际使用的功能,您可以创建更健壮、松耦合的系统,这些系统更容易测试、重构和维护。
在 JavaScript 中遵循 ISP 时
这些实践可以带来更模块化的代码,减少依赖性并增加灵活性。