如何调用最具体版本的重载方法?

时间:2012-07-21 02:50:13

标签: java dispatch

我有一个原始的碰撞系统,它检查每对物体是否有碰撞。

int size = drawables.size();
for(int i = 0; i < size; ++i)
{
    for(int j = i+1; j < size; ++j)
    {
        Drawable drawable = drawables.get(i);
        Drawable drawable2 = drawables.get(j);
        if(CollisionDetector.areColliding(drawable, drawable2))
        {
            CollisionHandler.handleCollision(drawable, drawable2);
        }
    }
}

CollisionDetectorCollisionHandler都有各自功能的通用和特定版本,例如

public static boolean handleCollision(Drawable drawable1, Drawable drawable2)
public static boolean handleCollision(Player player, SolidRectangle rectangle)
public static boolean handleCollision(Player player, Snowflake snowflake)

其中PlayerSolidRectangleSnowflake都延伸Drawable。我希望上面的循环调用每个可用方法的最具体版本,但是目前它只调用超类Drawable的那个。有没有办法在没有通过instanceof手动检查类的内容的情况下执行此操作?

我可以从以下示例中看到这可能是不可能的:如果B extends AC extends A并且我写了方法

public void foo(A a, C c)
public void foo(B b, A a)

然后

A objectB = new B();
A objectC = new C();
foo(objectB, objectC);

foo的召唤是模棱两可的,但我希望有人可能比我更了解此事。有没有办法解决这个问题?

2 个答案:

答案 0 :(得分:3)

Visitor Design Pattern提供了Java中multiple dispatch的替代方法。

除此之外,还有一些选择:

有一个过时的MultiJava Project在Java中实现了多个调度支持,还有一些其他项目使用反射来支持Java中的多方法:Java MultimethodsJava Multimethods Framework。也许还有更多。

您还可以考虑使用支持多方法的替代基于Java的语言,例如ClojureGroovy(这些链接指向示例)。

答案 1 :(得分:1)

您还需要确保CollisionHandler.handleCollision(a,b)等同于CollisionHandler.handleCollision(b,a)。正常方法调度解决了一半问题:

drawable.handleCollision(drawable2)

但是,正确地尝试实现equals()在不同类型的对象之间工作所需的(稍微繁琐)检查。

从概念上讲,您似乎正在寻找一种方法来选择要根据运行时类型的(无序)调用的函数。像HashMap<Set<Class>,CollisionHandler>之类的东西,除了最后我检查过的Java不支持泛型泛型(并且集合可能效率不高)。这些方面最有效的解决方案是通过反射填充HashMap<ClassPair,CollisionHandlerFunctor>(确保你同时获得ClassPair(Player.class,Snowflake.class)和ClassPair(Snowflake.class,Player.class),但即便如此似乎不是很有效率。