写出好维护的程式码 — 高内聚

2025年6月10日

💎 加入 E+ 成長計畫 如果你喜歡我們的內容,歡迎加入 E+,獲得更多深入的軟體前後端內容

写出好维护的程式码 — 依赖注入 (Dependency Injection) 与控制反转 (Inversion of Control) 主题文中,我们谈了透过依赖注入 (dependency injection) 与控制反转 (inversion of control) 这两个手段把程式码的耦合度降低,让程式码更容易维护。

当提到耦合度,相信多数读者都听过「高内聚、低耦合 high cohesion, low coupling」这个原则,在 写出好维护的程式码 — 依赖注入 (Dependency Injection) 与控制反转 (Inversion of Control) 主题文中我们主要在谈如何降低耦合,而在这期主题文,我们会专注在「高内聚」的概念上。

从日常生活的例子来理解内聚

在实际谈程式撰写时的高内聚之前,想先用一个生活化的例子跟大家谈「内聚」是什么概念。

以多数人都熟知的厨房为例,在一个料理新手的厨房中,可能因为本身对不同的器具与调味料不熟,所以可能会把所有的东西都塞在一起。这种状况下,假如今天要煮一道菜,光是找要用的工具以及搭配的调味料,可能就需要先花不少时间。

然而,假如有看过餐厅中专业厨师所使用的厨房,多半会发现整体的动线是精心设计过,不同的厨具、食材、调味料的位置摆放,也都是有缜密的计算,让厨师能够在最短的时间拿到自己要用的厨具、食材与佐料。

举例来说,一个常见的分类方式是把肉类跟蔬菜分开来放,在肉类中不同的肉也会有不同的收纳,牛肉不会跟鱼肉混在一起,这样要烹调牛肉相关的料理时,可以非常迅速地找出来。

当然,有些厨房可能会有不同的分类。举例来说,有些铁板烧店之所以整体运作效率非常高,其中一个原因是它们把热门餐点所需的材料,全都事先整理好了。所以当点了沙朗牛排,厨师可以直接拿出要煎那道牛排所需的所有东西,从牛肉本身到相关配料。

上面的这个例子,就是高内聚的表现。例子中的沙朗备盘,是单一职责、单一目的,其存在就是为了让厨师能煎出美味的沙朗牛排。在沙朗备盘中,没有任何跟要煎沙朗牛排无关的东西,里面有的材料全都是与制作沙朗牛排相关。

抽象一点来说,高内聚是指「把相关的东西聚在一起,借此达到单一目的」,所以备盘的单一目的,以及盘中的东西都是高度相关,就是高内聚的展现。

而当这样准备,就能够让厨师运作起来很高效,因为不用为在煎沙朗牛排时,还要在混杂着甜点佐料的区域找调味料;因为不用大范围的东翻西找,这能让速度变快,也能避免拿错东西。

什么是高内聚? 有什么好处?

希望透过上面的例子,读者们对于高内聚是什么,有比较具体的理解。在这个段落,让我们把重点拉回软体工程的领域中。在软体工程中,所谓的高内聚是指,把相关的东西聚在一个模组 (例如某个类别或函式)当中,让该模组有单一且定义清楚的职责。

因此在检视一个类别或函式时,如果该类别或函式有一个清楚的目的,且类别与函式当中的内容,彼此相近,且仅为该目的而存在,这样就会说是高内聚。反之,如果一个类别或函式,做了很多事,且做的事情彼此没关联,就会被认为是低内聚。

写程式时到底要拆开还是要聚在一起?

在理解完高内聚的定义与好处后,相信有些读者这时可能会有个疑问,那就是「高内聚、低耦合」这句话似乎有一点彼此相冲突,高内聚在讲要把相近的东西聚在一起,这样跟耦合在谈的要把东西拆开、抽出去似乎有点相违背。

关于这个问题,在《Balancing Coupling in Software Design》一书当中,作者 Vlad Khononov 谈到一个很精辟的点。他说内聚是指「模组当中,要素之间彼此相近的程度」。换句话说,内聚本身就是一种耦合。只是内聚的耦合是一种「好耦合」 (作者的原文是写 cohesion as “good coupling”)。

之所以说这个说法精辟,是因为在写程式时,总是不免有东西要放一起,只是当放在一起时,如果又要担心耦合的揉杂,可能会让大家在写程式时有所顾忌。但如果用「好耦合」的角度来看,假如某些东西彼此足够相近,放在一起能带来上述高内聚的好处,那么即使放在一起有耦合也无妨。

因此,在思考高内聚时,推荐读者们可以从「好耦合」的角度来看,推荐可以思考「哪些东西放在一起会让未来要维护时可以更容易」,借此来决定什么要放一起、什么要拆开。

高内聚与低耦合,检视的角度有所不同

除了上一段落的角度外,在看「高内聚、低耦合」时,也推荐读者们可以用不同的视角来看。

具体来说:

  • 高内聚是在检视「模组之内」,确保模组内的东西高度关联,专注在单一目标
  • 低耦合是在检视「模组之间」,确保模组间不相互纠缠,避免牵一发动全身的状况

事实上,这两种是相辅相成的,当今天如果我们确保一个模组是高内聚的,就能同时确保这个模组有清楚的边界,这样跟其他模组之间也比较容易是低耦合的。

阅读更多

如果读者们想更了解高内聚这个主题,并有具体的程式码案例分析,以及高内聚在软体工程其他面向的应用,我们在 E+ 成长计划的主题文中,都有更详细谈。感兴趣的读者,可以在以下连结看到 E+ 的详细介绍 (连结)。

本文为 E+ 成长计划的深度内容,截取段落开放免费阅读。欢迎加入 E+ 成长计划阅读完整版本 (点此了解 E+ 的详细介绍)。

🧵 如果你想收到最即時的內容更新,可以在 FacebookInstagram 上追蹤我們