反if目的:如何检查空值?

3
我最近听说了 反if运动 以及一些面向对象编程大师为了避免使用 if 而使用多态的努力。但我不明白这样该如何实现,我的意思是说,它应该始终如一地工作。

我已经在使用多态(不知道反if运动),所以我对“坏”和“危险”的if很感兴趣,我查看了我的代码(Java / Swift / Objective-C)以看到我使用if的情况最多,看起来这些是情况:

  1. 检查空值。这是我使用if语句最常见的情况。如果一个值可能为null,我必须以正确的方式处理它。相反,我需要检查它不是null才能使用它。我不知道多态性如何在没有if语句的情况下弥补这一点。
  2. 检查正确的值。我将在这里举个例子:假设我有一个登录/注册应用程序。我想检查用户是否实际上写了密码,或者它是否超过5个字符。如果没有if/switch语句,这怎么可能完成?再次强调,这与类型无关,而与值有关。
  3. (可选)检查错误。这是可选的,因为它与第2点关于正确值类似。如果我在块/闭包中传递一个值或错误对象(作为参数),如果我不能检查它是否为null或不存在,我该如何处理错误对象?

如果您对此活动有更多了解,请在此范围内回答。我问这个问题是为了了解他们的目的以及他们所说的内容可以有效地完成的程度。

所以,我知道完全不使用if语句可能不是最明智的想法,但只是询问在OOP程序中是否可以有效地使用if语句以及如何使用。


1
一些关于将条件语句替换为多态的阅读材料 https://sourcemaking.com/refactoring/replace-conditional-with-polymorphism - dbugger
4个回答

4

你永远无法完全摆脱if,但可以将其最小化。

关于空值检查,一个本来会返回空值的方法可以返回一个Null Object,而不是表示真实值的对象,但实现了一些与真实值相同的行为。它的调用者只需在Null Object上调用方法,而无需检查它是否为空。该方法内可能仍然存在if,但调用者不需要。

关于正确值检查,最好的方法是防止使用不正确属性实例化对象。所有对象的用户都可以确信,他们不必检查对象的属性就能使用它。同样,如果对象可以具有有效或无效属性,则可以通过提供适用于当前属性值的正确操作的高级方法来隐藏其属性。同样,在该对象内部仍然存在if,但调用者不需要。

关于错误检查,有几种比返回可能为空的错误值更好的策略。其中一种是引发异常。另一种是返回一个可以容纳结果或错误的类型对象,并提供类型安全,无需使用 if 即可在适当时操作任一结果的方式,例如Java的 Optional 或Haskell的 Maybe
还要注意, case 语句只是连接的 if (实际上,我会用 switch 而不是 if / else if 编写 campaign 主页上的代码),并且还有用多态替换 case 的模式,例如策略模式

抛出异常应该是最后的选择。正如您所建议的那样,使用包含预期对象或适当错误的结果对象会更加清晰易懂。 - dbugger
你必须小心,以免过火,否则每个方法都变成一个TryXYZ方法。我不完全确定是否想回到旧有的方式,其中需要检查每个操作的错误代码。 - Lasse V. Karlsen
Objective-C实际上在这方面有所帮助,因为您可以在nil上发送消息(调用方法),而不会产生任何后果。在Java中会抛出NPE异常,而Objective-C只是说¯\(ツ)/¯。 - Chris Thompson

4
这是一个很好的问题,也是我参加过的每个面向对象编程营中都会被问到的问题。首先,我们需要理解为什么有很多if语句的代码是“不好”的或“危险”的:
  • 它们增加了代码的圈复杂度,使其难以跟踪/理解。
  • 它们使测试变得更加复杂。确保在测试方法下的每个分支流中进行测试变得越来越困难,并使测试设置繁琐。
  • 它们可能表明您的代码没有分成足够小的方法。
  • 它们可能表明您的方法封装得不够好。

然而,有一件重要的事情要记住- if语句不能(也不应该)完全从代码中消除。但是,我们通常可以使用诸如多态性、提取小行为和将这些行为封装到适当的类中等技术来抽象它们。

现在我们知道了一些应避免if语句的原因,让我们回答你的问题:

  1. 检查是否为null值:Null object pattern可以帮助你在代码中消除null检查(多态性胜利)。不返回null,而是返回一个特殊情况的NullObject表示所期望的对象。这个NullObject与实际对象具有相同的接口,调用任何对象方法时都可以放心,不必担心出现空指针异常。

  2. 检查值的正确性:有很多方法可以实现。例如,你可以为每个验证创建一个单独的ValidationRule类,当你想要验证对象时,将它们链接在一起。注意,ifs仍然存在,但它们被抽象成单独的ValidationRule实现。寻找Command patternChain Of Responsibility pattern以获取更多创意。


关于空对象模式,当处理过程需要通知值的缺失时,您如何处理?我认为Maybe或Optional单子更有趣,因为方法契约规定该值可能不存在。 - plalx

-1

最好使用if来检查null而不是引发异常。此外,在常见情况下,检查null可以帮助我们防止对未初始化变量进行操作。


这不是我的问题的重点... 我不是在谈论删除类型安全性,而是用一种不同的方式来实现它。例如,在Swift中,使用可选项可以确保如果您具有非可选类型,除非您有意强制解包可选类型,否则它不会为null。 - BlackBox
还有一种方法是使用switch结构和多态方法。 - Alex Planida
我们可以简单地遵循SOLID原则。 - Alex Planida

-1

使用 switch 加上 SOLID。其他的从中继承。


2
一个Switch语句只是增强版的if语句,通常本身就是代码异味。 - dbugger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接