问题描述
我正在用 ruby 处理二维形状。我有一个带有 x 和 y 属性的 Point 类,以及一个有两个端点的 Line 类。在流程链的后期,我经常希望识别和处理垂直线与水平线略有不同,即使两者都可能出现在同一组线中。我有混合来做处理,但我经常发现这个方法有类似
if l.vertical?
l.do_something_with_y_coordinate
elsif l.horizontal?
l.do_something_with_x_coordinate
end
我经常看到这种模式,我不喜欢重复。我可以通过识别垂直的 Line 实例并创建一个 VerticalLine 类和一个 HorizontalLine 类来尝试避免它,但这感觉更像是 .Net 而不是 ruby 并且不会减少重复,只是封装了它。
另一种方法可能是使用返回 :x 或 :y 的方向方法,然后使用返回“do_something_with direction”的方法。
还有其他人对如何重构有任何建议吗?
解决方法
它不是“更像 .Net”,它更像是适当的面向对象封装。如果您是通过 .Net 了解到的,那很好,但这是一种非常通用的方法,可以追溯到 .Net 或 Ruby 出现之前的几十年。
有三种方法可以解决这个问题:
- 使用
if
来拆分行为。 - 使用子类来实现特定的行为。
- 概括您的代码,使其无论是垂直的还是水平的都无关紧要,在这两种情况下都应用相同的数学方法。
在第三种情况下,想象一下有向量或矩阵来描述您正在操纵的几何图形。例如,[0,1]
可以表示向上的垂直线,或 [-1,0]
向左的线,具体取决于您的坐标系。每次迭代您只需将其添加到您的基点。水平或垂直的概念消失了。
在具体案例中,我看到了三个建议:
1.) 根据两种情况定义映射到 x
和 y
的访问器:
def s=(value)
if horizontal
x = value
else
y = value
end
end
def t=(value)
if horizontal
y = value
else
x = value
end
end
有了这个,您可以动态地委派给“正确”的字段。
2.) 通过旋转将水平案例转换为垂直案例,然后执行操作,然后将其旋转回来。
3.) 使用另一种不使用 x
和 y
的表示,例如您的微分消失的极坐标。