重构:保护条款

2025-06-04

重构:保护条款

在计算机编程中,保护是一个布尔表达式,如果程序要在相关分支中继续执行,则其计算结果必须为真。

无论使用哪种编程语言,保护代码或保护子句都是用于检查完整性前提条件,以避免执行期间出现错误。——维基百科

未应用保护子句技术的代码中主要存在以下问题:

  1. 过度缩进。如果嵌套使用过多的控制结构,则会导致缩进级别过高,从而增加代码阅读难度。

  2. if-else之间的关系。当if-else之间存在大量单独的代码片段,而这些代码片段在概念上彼此相关时,需要通过在不同部分之间跳转来执行代码阅读。

  3. 脑力劳动。源代码中不同跳转的结果会导致在代码生成过程中产生额外的努力。

因此,保护​​条款的实际应用如下情况:

在这种情况下,大多数情况下,你必须反转逻辑以避免使用保留字 else。之前的代码可以重写如下:

因此,导致方法退出的特殊情况将被放置在方法的开始处,并充当保护,以避免继续通过方法的令人满意的流程。

这样,该方法就很容易阅读,因为具体情况都在方法的开头,而令人满意的流程使用情况是该方法的主体。

有人反对使用保护子句,他们认为每个方法应该只有一个出口点,而使用这种技术我们可以找到多个出口点。这不应该与在方法中到处返回且不受控制的情况相混淆,因为后者会让我们付出更大的脑力劳动。但是,所有返回都受到明确的控制,因为它们会在保护子句中或方法的末尾找到。

下面我们将看到更复杂的保护子句的例子,其中代码的阅读和理解得到了显著的提高。

假设您需要创建一个方法来计算健康保险的费用,该方法接收用户 ID 作为参数。
使用此 ID 在数据库中搜索用户。如果用户不存在,则会抛出 UserNotFoundException 异常。如果系统中存在该用户,则下一步是验证用户的健康保险是否符合此算法适用的保险类型:Allianz 或 AXA。如果保险无效,则必须返回 UserInsuranceNotFoundException 异常。最后,此算法仅对西班牙国籍的用户有效。因此,您应该再次检查用户是否是西班牙人,以便进行保险计算,否则将返回 UserIsNotSpanishException 异常。

如您所见,代码有多层缩进。下面显示的是与上一个算法相同的版本,但应用了保护子句技术。这项技术使代码更具可读性。请注意,我们应用了 3 个保护子句,它们允许生成不影响算法结果的替代路径(抛出异常)。

一些必须解决的问题:

  1. 为什么没有 if-else if 的情况?

  2. 别再想了!如果你的代码需要像 else if 这样的用例,那是因为你违反了单一职责原则,并且代码会做出更高层次的决策,应该使用诸如划分为子方法之类的技术或诸如命令策略之类的设计模式来进行重构

  3. 负面条件尚不十分清楚。

  4. 为此,我们提出了另一种重构技术,称为“方法提取”,即将代码提取到函数中,以便于复用或阅读理解。在下面的示例中,我们修改了上一个示例,创建了一些方法,以便更好地阅读和理解代码。

在使用子句保护时,条件的逻辑通常是颠倒的,并且根据条件的复杂性,理解在该条件下正在评估的内容是相当复杂的。

这就是为什么在小函数中提取条件逻辑是一种很好的做法,这样可以提高代码的可读性,当然,还可以发现其中的错误,因为评估条件的责任被委托给了特定的函数。

对于我们的医疗保险示例,我们可以生成以下方法:

无需创建函数来检查用户是否存在,因为只需检查用户是否为 null 或 undefined 即可。因此,最终代码如下:

为了提高代码质量,有很多实践。应用重构技术时,最重要的是要学习关注两点,主要包括:

  1. 解耦代码,使得小的更改不会引起整个软件项目的大规模链式更改。

  2. 可读性,开发人员必须明白,他们的大部分工作时间都花在阅读代码上,而且很可能是其他开发人员编写的代码。如果开发人员不需要花时间去理解那些难以阅读的基本逻辑,那么在成本/开发方面就非常有利了。

重构从最基础的点开始,从一个简单的if,到架构模式。照顾到软件开发的各个方面都很重要。

Refactoring.com
Guard — 维基百科

最初于 2019 年 5 月 31 日发布于https://carloscaballero.io 。

文章来源:https://dev.to/carlillo/refactoring-guard-clauses-4ee6
PREV
理解:Paw Patrol 解释的 JavaScript 中的上下文、范围、执行上下文和 8 种不同的 This 值!
NEXT
ES2018 特性及简单示例