我正在为以下相当微不足道的问题寻找OOP设计建议。我想避免使用类型内省(例如Java instanceof
运算符)而不使用访问者模式,这是典型的建议。我现在用Java编写这个,但我认为这个问题比Java更普遍。
问题背景:我正在为物理模拟编写一个简单的碰撞求解器。我目前有两种类型的边界体积,轴对齐边界框(AABB)和边界球体。模拟包含一组对象,这些对象可以使用任一类型的边界体积进行碰撞检测。作为碰撞求解器的一部分,我有一个“重叠测试器”对象,如果两个给定的边界体积相交,它只返回true。这是一幅草图:
interface BoundingVolume {
...
}
class AABB implements BoundingVolume {
...
}
class BoundingSphere implements BoundingVolume {
...
}
class OverlapTester {
static boolean overlaps(BoundingVolume a, BoundingVolume b) {
if (a instanceof AABB && b instanceof AABB) {
...
} else if (a instanceof AABB && b instanceof BoundingSphere) {
...
} ...
}
}
class Simulation {
List<BoundingVolume> simObjectBVs;
void collide() {
for (BoundingVolume a : simObjectBVs) {
for (BoundingVolume b : simObjectBVs) {
if (a != b && OverlapTester.overlaps(a, b)) {
...
}
}
}
}
}
实际上,overlaps
方法有一个4向if-else语句,用于将参数向下转换为AABB
或BoundingSphere
并调用适当的重叠方法。这是我想避免的。
典型的建议是为每个overlaps
和AABB
类型添加BoundingSphere
方法,这些方法知道如何测试自身是否与其他类型的边界体积重叠(我认为这符合访客模式)。但是,我不认为这是最合适的:稍后添加新类型的边界卷时,我必须更新每个其他类型的边界卷,以便为新类型添加重叠方法。但是,如果OverlapTester
包含所有这些逻辑,我只需要在一个地方添加一个新方法。
这里是否有其他模式可以满足我的需求,或访客模式是否真的最适合?
答案 0 :(得分:2)
我的英语不是很好,但我希望它有所帮助
根据我的理解,你有两种物体,每种物体都有自己的坐标系,你需要知道在给定的空间中它们的体积是否发生碰撞。
如果这是正确的,我假设你在那个空间中使用某种类型的坐标系统(笛卡儿,球形......)那么,我会做的是以下内容:
每个BoundingVolume
应该知道如何翻译&#34;他们自己的坐标系统到一般的模拟坐标系,每个BoundingVolume
的父亲应该知道如何比较这些卷,现在每个卷都在同一个坐标系中。
实施例
public abstract class BoundingVolume {
public abstract CartesianVolume getCartesianVolume();
public final boolean overlaps(BoundingVolume bV) {
boolean ret = false;
CartesianVolume thisCartesianVolume = this.getCartesianVolume();
CartesianVolume otherCartesianVolume = bV.getCartesianVolume();
// Decide whether they overlap or not, and return proper boolean value
return ret;
}
}
public class AABB extends BoundingVolume {
public CartesianVolume getCartesianVolume() {
// Code returning the object CartesianVolume with proper Volume
}
}
public class BoundingSphere extends BoundingVolume {
public CartesianVolume getCartesianVolume() {
// Code returning the object CartesianVolume with proper Volume
}
}
这样一来,你应该确实实现一个新的类,笛卡尔音量,如果你没有类似的东西来管理模拟空间。但是,如果添加新的BoundingVolume类型,则只需要实现其getCartesianVolume()
,即使使用新类型,父亲也会知道该怎么做。