菜单

组合优于继承

相关源文件

目的

本页面解释了 JavaScript 类设计中组合与继承的概念,以及何时优先选择其中一种方法。它为通过对对象关系做出适当的架构决策来编写可维护、灵活的代码提供了指导。

介绍

在面向对象编程中,建立类之间关系主要有两种方式:继承和组合。整洁代码原则“组合优于继承”指导开发人员在设计类关系时优先考虑组合,尽管继承在特定场景下仍然适用。

来源: README.md1309-1317

理解这两种方法

继承

继承在类之间创建“是-A”关系。子类从父类继承属性和方法,并可以扩展或覆盖它们。

来源: README.md1194-1224

组合

组合创建“拥有-A”关系。类不是继承,而是将其他类的实例作为属性包含在内,并委托给它们。

来源: README.md1355-1374

何时使用继承

根据整洁代码指南,继承适用于以下特定场景:

  1. 是-A关系:当子类确实是父类的特化版本时(例如“人类是动物”)
  2. 基类代码复用:当子类可以通过继承功能获益时(例如“人类可以像所有动物一样移动”)
  3. 对派生类的全局更改:当您需要通过修改基类来对所有派生类进行系统性更改时

来源: README.md1319-1326

何时使用组合

在以下情况应优先考虑组合:

  1. 拥有-A关系:关系表示包含而非特化
  2. 灵活的行为组合:当类需要以不适合严格继承层次结构的方式组合行为时
  3. 避免紧密耦合:防止当父类更改时导致脆弱的继承层次结构崩溃

来源: README.md1355-1374

实际示例

README 文件提供了一个明确的例子,说明组合优于继承

有问题的继承方法

在此示例中,EmployeeTaxData 继承自 Employee,创建了一个不准确反映现实的“是-A”关系——税务数据不是员工的一种类型。

来源: README.md1330-1349

更好的组合方法

组合方法正确地建模了员工“拥有-A”税务数据组件的关系

来源: README.md1355-1374

优点和缺点

方法优点缺点
继承- 清晰表示“是-A”关系
- 相关类之间的方法复用
- 对基类的更改会传播到所有派生类
- 造成类之间的紧密耦合
- 当父类更改时易碎
- 在 JavaScript 中仅限于单继承
- 可能导致深层继承层次结构
组合- 更灵活、模块化的设计
- 更容易在运行时修改行为
- 更清晰的封装边界
- 组件间耦合度更低
- 可能需要更多代码来委托操作
- 关系可能不如继承明显
- 可能需要额外的接口设计

来源: README.md1309-1376

决策指南

在选择继承和组合时,请问自己以下问题:

  1. 这真的是“是-A”关系,还是“拥有-A”关系?
  2. 对父类的更改是否可能破坏子类?
  3. 您是否需要重用公共基类中的方法和属性?
  4. 类之间的关系是稳定的,还是可能会演变?

如果关系是“拥有-A”或您需要灵活性,那么组合通常是更好的选择。

来源: README.md1309-1326

总结

虽然继承是面向对象编程的强大特性,但组合通常能带来更灵活、更易于维护的代码。通过组合来建模关系,您可以创建更易于修改、扩展和测试的系统。请记住这个原则:“在可能的情况下,优先选择组合而非继承”,但请根据您的具体要求选择合适的方法。

来源: README.md1309-1317