java - 如何使用双重调度来分析图形基元的交集?

标签 java graphics double-dispatch

我正在分析图形基元(矩形、直线、圆形等)的交互并计算重叠、相对方向、合并等。这被引用为双重调度的一个主要示例(例如 Wikipedia )

Adaptive collision algorithms usually require that collisions between different objects be handled in different ways. A typical example is in a game environment where the collision between a spaceship and an asteroid is computed differently than the collision between a spaceship and a spacestation.1

但我还没有理解主要的解释,而且我一般也不理解SO上的答案。

我当前的代码(Java)使用父类(super class) Shape,类似于:

for (int i = 0; i < shapes.size() - 1; i++) {
    for (int j = i + 1; j < shapes.size(); j++) {
        Shape shape = shapes.get(i).intersectionWith(shapes.get(j));
    }
}

在子类(此处为 Rect)中具有特定实现,例如

public class Rect extends Shape {

    public Shape intersectionWith(Shape shape) {
        if (shape instanceof Rect) {
            return this.getCommonBoundingBox((Rect)shape);
        } else if (shape instanceof Line) {
            return this.intersection((Line)shape);
        } else if (shape instanceof Text) {
            return this.intersection((Text) shape);
        }
    }
}

无论如何我都必须编写所有n*(n-1)/2方法(并且已经这样做了)。我还必须有可扩展的代码以适应(比如说)以后的情况:

        } else if (shape instanceof Circle) {
            return this.intersection((Circle)shape);

我不知道如何使用双分派(dispatch)模式,也不知道它的值(value),并且希望有一个使用 Java 图形基元或类似伪代码的具体示例。

更新:我已经接受@Flavio,因为(我认为)它回答了所提出的确切问题。然而,我实际上已经实现了@Slanec,因为它解决了我的问题,并且(对我来说)更简单、更容易阅读。我有一个附属问题“解决方案是否取决于对称关系?”。

“A 与 B 相交”通常与“B 与 A 相交”相同,但“A 与 B 碰撞”并不总是与“B 与 A 碰撞”相同。 (A == 汽车,B == 骑自行车的人)。可以想象,我的交集在未来可能不对称(例如“矩形部分遮盖圆”不是对称的,并且可能具有不同的语义。

@Flavio 很好地解决了维护问题,并指出编译器可以检查问题。 @Slanec 通过反射来做到这一点,看起来好像它是一个有用的维护辅助工具 - 我不知道性能损失是什么。

最佳答案

您可以通过Visitor模式在Java中实现双重调度。

public interface ShapeVisitor<P, R> { 
    R visitRect(Rect rect, P param);
    R visitLine(Line line, P param);
    R visitText(Text text, P param);
}

public interface Shape {
    <P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor);
    Shape intersectionWith(Shape shape);
}

public class Rect implements Shape {

    public <P, R> R accept(P param, ShapeVisitor<? super P, ? extends R> visitor) {
        return visitor.visitRect(this, param);
    }

    public Shape intersectionWith(Shape shape) {
        return shape.accept(this, RectIntersection);
    }

    public static ShapeVisitor<Rect, Shape> RectIntersection = new ShapeVisitor<Rect, Shape>() {
        public Shape visitRect(Rect otherShape, Rect thisShape) {
            // TODO...
        }
        public Shape visitLine(Line otherShape, Rect thisShape) {
            // TODO...
        }
        public Shape visitText(Text otherShape, Rect thisShape) {
            // TODO...
        }
    };
}

当您添加新的 Shape 子类时,您必须向 ShapeVisitor 接口(interface)添加一个新方法,并且您会因缺少的所有方法而收到编译错误。这很有用,但如果您正在编写一个库并且允许您的用户添加 Shape 子类(但显然不能扩展 ShapeVisitor 接口(interface)),则可能会成为一个大问题。

关于java - 如何使用双重调度来分析图形基元的交集?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19400582/

相关文章:

java - JSP页面刷新时清除数据

java - 如何让 java webservices 使用扩展类

c++ - 在不使用 graphics.h 的 pieslice() 的情况下,在 C 中生成一个 "pieslice"

design-patterns - 我需要询问对象类,但这是一种不好的做法。这种情况的替代方案?

java - 避免与 Kotlin 泛型内联

Java 相当于 register int?

R:在水平图中显示按分组变量分层的值

java - 如何在 JRadioButtons 中使用 ActionListener

c# - 双重 dispatch 和备选方案

javascript - JavaScript 中动态类型运算符的双重调度