Lumen

Lumen

Eager to know more, about the world, about the intelligence, and about myself.
github

组合优于继承

为什么 “优先考虑组合而非继承”?#

在最近的一篇文章中,我分享了我对项目代码库复杂性的沮丧。基本上,它太复杂且交织在一起。尽管我感到不适,但我必须找到一个解决方案,这让我接触到了设计模式。

我听到的一个原则是 “优先考虑组合而非继承”。起初,我对这两者之间的区别只有模糊的理解,更不用说如何在我的项目中实现这个概念了。然而,这段来自 ArjanCodes 的视频帮助我理解了其背后的理由,我现在将对此进行解释。

耦合造成复杂性#

在设计项目时,特别是在面向对象编程中,由于不同对象之间的交互和依赖,复杂性可能迅速升级。这种复杂性源于耦合

复杂的耦合可能导致几个问题。它可能使修改和添加新功能变得艰巨,因为你必须考虑不同对象之间错综复杂的相互作用。更改可能在整个代码库中产生不可预见的后果。此外,单元测试在高度耦合的代码中变得更加困难,因为你需要测试所有场景以实现足够的覆盖率。

下面的图表说明了系统耦合的不同级别。高度耦合的系统需要测试所有可能的输入组合。然而,通过将计算解耦为步骤,每个函数可以通过检查单个输入及其对应的输出来验证,这样测试起来要容易得多。

Mermaid Loading...
不同耦合级别的比较

复杂的继承结构引入耦合#

借鉴 Arjan 的例子,在纯粹基于继承的方法中,一个Employee类可能封装与员工相关的所有操作,例如 ID、年龄、性别和支付方式。对于每种员工类型,你创建一个从基类派生的子类。这种方法通过继承解决问题。

然而,如果你将所有责任分配给一个单一的Employee类,随着项目的增长及其不断变化的需求,最终将导致一个庞大的层次结构树。每个部分都依赖于其父类,导致共享同一父类的子类之间产生间接耦合。修改任何基类可能会导致混乱。如果一个新变体对你现有实现有甚至是微小的不兼容要求,你可能不得不从一个非常基础的类继承并重新实现所有功能。简而言之,继承造成耦合,过度使用它会使你的工作变得复杂而不是简单。

Mermaid Loading...
复杂的继承树

优先考虑接口#

问题并不是说我们不应该创建复杂的系统,而是确保这些系统内组件的逻辑分离。如果我们检查之前的例子,Employee类由于被分配了多个责任而显得问题重重。它细分了不同的员工类型,并管理各种支付和佣金,这些任务可以由单独的实例处理

为了解决这个问题,我们可以为不同的合同类型创建一个Contract类,为各种佣金创建一个Commission类。然后可以将这些实例传递给Employee类。只要这些保持统一的接口,我们的任务就变得简单得多。

Mermaid Loading...
这看起来好多了,不是吗?

结论#

设计模式对我来说是相当新的,但我可以大致理解它们的目标 —— 降低系统的复杂性,并尽可能使其模块化。

“组合优于继承” 的理念在抽象层面上与依赖注入非常相似。它们都是表达同一目标的不同术语,旨在分离和保持局部的简单性,从而增强代码的可维护性和灵活性。

参考文献#

为什么组合优于继承 - 详细的 Python 示例

Python 中的依赖反转与依赖注入

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。