使用多态性替换空检查

时间:2019-01-15 21:20:49

标签: design-patterns polymorphism

最近,我正在阅读罗伯特·马丁(Robert Martin)的书“干净的代码”,在第7章中有一段,他说您应该尝试使用特殊情况设计模式替换空检查。我以为这是个好主意,但后来想到了以下情况。

foreach(thing in someCollection) {
    value = getValue();
    if(value == null) {
        break;
    }
    value.doSomething();
}

您可以这样做,以使getValue返回的对象是多态的,创建一个强制执行doSomething()方法的接口,并为您要返回的对象实现该接口,并为该对象的“ mock”类特殊情况(如果值为null)。这将消除对gaurd子句的需要,因为如果在我们的“模拟”对象上调用doSomething()并不重要,因为它是具有doSomething()方法的实际对象:

 function doSomething(){
    return;
 } 

唯一的问题是,循环不会中断。据我所知,如果返回了“模拟”对象,则没有办法使用多态类打破循环,除非您对模拟对象进行了检查,但是那样就无法解决问题了。

我的问题是,有没有一种干净的方法来处理不会引起这种计算损失的空值?还是我对第7章关于空值检查的内容有误解?

2 个答案:

答案 0 :(得分:2)

大概break是为了防止NullPointerException,因为已经到达集合的末尾。如果目标不是 filter 集合,则应该保证使用更合适的结构(例如Predicate)(并且更具可读性)。

从高层次看,您已经观察到将小的OO构造放入一批过程代码中可能需要重新考虑以前的设计。这通常是正确的。如果将null用作集合中间的断点,则在实现空对象模式之前,需要考虑更大的设计问题。

尽管对于空对象模式(在重构循环之后)这仍然是一个不错的方案,但该模式并不适用于所有使用null的方案。不幸的是,这并不是那么简单。 Optional是一种更受欢迎的解决方案,并且还有更多。

答案 1 :(得分:2)

特殊情况模式或空对象模式用于统一处理所有情况。这样可以避免客户端代码具有多个执行路径。

在您给出的示例中,特殊情况必须区别对待,因为遇到特定值时必须停止迭代(在这种情况下为null)。您不能为问题X应用解决方案来解决问题Y,尤其是当两个问题完全相反时。