例子:与复杂的逻辑战斗
假设你在实现下面这个Range类:
下图给出一些范围的例子:
请注意终点是非包含的。因此A、B和C互相之间不会有重复,但是D与所有其他重复。
下面是对OverlapsWith()实现的一个尝试——它检查是否自身范围的任意一个端点在other的范围之内:
尽管只有两行代码,但是里面包含很多东西。下图给出其中所有的逻辑。
这里面有太多的情况和条件要去考虑,这很容易滋生bug。
说到这儿,这里还真有一个bug。前面的代码会认为Range[0,2)与Range[2,4)重复,而实际上它们并不重复。
这里的问题是在比较begin/end值时要小心地使用<=或<。下面是对这个问题的修正:
现在已经改正了,是吗?实际上,还有另一个bug。这段代码忽略了begin/end完全包含other的情况。
下面是处理这种情况的修改:
现在代码变得太复杂了。你不可能指望别人看了这段代码就对它的正确性有信心。那么我们该怎么办?怎么拆分这个大的表达式呢?
找到更优雅的方式
这就是那种你该停下来从整体上考虑不同方式的时机之一。开始还很简单的问题(检查两个范围是否重叠)变得非常令人费解。这通常预示着肯定有一种更简单的方法。
但是找到更优雅的方式需要创造力。那么怎么做呢?一种技术是看看能否从“反方向”解决问题。根据你所处的不同情形,这可能意味着反向遍历数组,或者往回填充数据结构而非向前。
在这里,Overlap sWith()的反方向是“不重叠”。判断两个范围是否不重叠原来更简单,因为只有两种可能:
1.另一个范围在这个范围开始前结束。
2.另一个范围在这个范围结束后开始。
我们可以很容易地把它变成代码:
这里的每一行代码都要简单得多——每行只有一个比较。这就使得读者留有足够的心力来关注<=是否正确。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论