避免没有访客模式的类型内省

时间:2014-08-25 13:54:28

标签: java oop design-patterns

我正在为以下相当微不足道的问题寻找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语句,用于将参数向下转换为AABBBoundingSphere并调用适当的重叠方法。这是我想避免的。

典型的建议是为每个overlapsAABB类型添加BoundingSphere方法,这些方法知道如何测试自身是否与其他类型的边界体积重叠(我认为这符合访客模式)。但是,我不认为这是最合适的:稍后添加新类型的边界卷时,我必须更新每个其他类型的边界卷,以便为新类型添加重叠方法。但是,如果OverlapTester包含所有这些逻辑,我只需要在一个地方添加一个新方法。

这里是否有其他模式可以满足我的需求,或访客模式是否真的最适合?

1 个答案:

答案 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(),即使使用新类型,父亲也会知道该怎么做。