我最近听说了反if运动,以及一些OOP大师在没有ifs的情况下编写代码的努力,而是使用多态性。我只是不明白它应该如何工作,我的意思是,它应该如何始终工作。
我已经使用了多态性(不知道反 if 运动),所以,我对"坏"和"危险"的 if 很好奇,我去看了我的代码(Java/Swift/Objective-C),看看我在哪里使用最多的,看起来是这样的情况:
- 检查空值。这是我使用 if 的最常见情况。如果一个值可能为空,我必须以正确的方式管理它。要使用它,我必须检查它是否不为空。我不明白多态性如何在没有 ifs 的情况下弥补这一点。
- 检查正确的值。我将在这里做一个例子:假设我有一个登录/注册应用程序。我想检查用户是否确实写了密码,或者密码长度是否超过 5 个字符。没有 if/switch 怎么可能完成?同样,这不是关于类型,而是关于值。
- (可选)检查错误。可选,因为它类似于关于正确值的第 2 点。如果我在块/闭包中获得值或错误(作为参数传递),如果我无法检查它是否为 null,我如何处理错误对象?
如果您对此活动有更多了解,请在该范围内回答。我要求这样做是为了了解他们的目的以及如何有效地完成他们所说的。
所以,我知道根本不使用 ifs 可能不是有史以来最聪明的想法,而只是问它是否可以以及如何在 OOP 程序中有效地完成。
你永远不会完全摆脱if
,但你可以最小化它们。
关于 null 值检查,否则返回 null 值的方法可以返回 Null 对象,该对象不表示实际值,但实现与实际值相同的一些行为。它的调用方可以只调用 Null 对象上的方法,而不是检查它是否为 null。方法内部可能仍有if
,但调用方中不需要任何。
关于正确的值检查,最好的途径是防止使用不正确的属性实例化对象。然后,该对象的所有用户都可以确信他们不必检查对象的属性即可使用它。同样,如果对象可以具有有效或无效的属性,则可以通过提供对当前属性值执行正确操作的更高级别的方法,对其用户隐藏该属性。同样,对象内部仍然有一个if
,但调用方中不需要有任何。
关于错误检查,有几种策略比返回调用方可能忘记检查的可能为 null 的错误值更好。一是提出例外。另一种方法是返回一个类型的对象,该对象可以保存结果或错误,并在适当的时候提供类型安全的、if
无操作的方法来操作任一结果,例如 Java 的Optional
或 Haskell 的Maybe
。
另请注意,case
语句只是if
s连接起来的(实际上我会在活动的主页上用switch
而不是if
/else if
编写代码),并且还有一些模式用多态性代替case
,例如策略模式。
这是一个很好的问题,也是我参加过的每个OO训练营都会问到的问题。首先,我们需要理解为什么有很多if的代码是"坏的"或"危险的":
- 它们增加了代码的圈复杂性,使其难以理解/理解。
- 它们使测试编写起来更加复杂。对于每个条件,确保测试所测试方法中的每个分支流变得越来越困难,并且使测试设置变得繁琐。
- 它们可能表明您的代码尚未分解为足够小的方法
- 它们可能表明您的方法尚未很好地封装
但是,有一件重要的事情要记住 - ifs 不能(也不应该)从代码中完全消除。但是,我们通常可以使用多态性等技术将它们抽象出来,提取小行为,并将这些行为封装到适当的类中。
现在我们知道了我们应该避免ifs的一些原因,让我们解决您的问题:
检查空值:空对象模式可帮助您消除代码中的空检查(多态 FTW)。您不返回 null,而是返回预期对象的特殊情况 NullObject 表示形式。此 NullObject 具有与实际对象相同的接口,您可以安全地调用对象的任何方法,而不必担心引发空指针异常。
检查值的正确性:有很多方法可以做到这一点。例如,您可以为每个验证创建一个单独的 ValidationRule 类,然后在要验证对象时将对这些验证的调用链接在一起。请注意,ifs 仍然存在,但它们被抽象到各个 ValidationRule 实现中。查找命令模式和责任链模式以获取想法。
最好使用if
来检查null
,而不是引发异常。此外,在通常情况下,检查null
有助于我们防止使用非初始化变量进行操作。
使用switch
加 SOLID。其他思想由此继承而来。