要检查两个项目是否在空间上碰撞。为此,两个项目都用一些简化的几何形状表示-为简单起见,假设这些形状只能是圆形,多边形和直线。物品可以用这些形状中的任何一种来表示,并且碰撞检测需要能够处理任何可能的组合。我想找到一种策略,该策略涉及最少的代码重复,并允许将来添加更多形状。

我的方法如下:

public class Item{

   private Collidable bounds;

   public boolean checkCollision(Item target){
       return bounds.checkCollision(target.getBounds());
   }
}


其中Collidable是任何几何形状的界面,可能的形状如下所示:

public class Circle implements Collidable{

   public boolean checkCollision(Collidable target){
      if(target instanceof Cirlce){
         //Algorithm for circle-circle collision
      }else if(target instanceof Line){
         //Algorithm for circle-line collision
         //...
      }else{
         return false;
      }
   }
}


但是,这会产生大量代码重复(在Line类中需要重复相同的圆线碰撞算法),而且看起来不太好。我寻找了不同的设计模式来寻找解决方案,但最终还是得到了这种类似策略的解决方案。什么是更好的方法呢?

最佳答案

使用Visitor pattern恢复Collidable类型的信息。
圆圈不知道正在检查哪个图形有碰撞,但是图形知道。让我们用double dispatching找出来。

您可以重命名这些方法,但含义应保持不变。您也可以将这些方法标记为internal,以便不能在其他上下文中调用它们。

您可以将检查特定对的方法委托给外部静态类,以避免代码重复。

public interface Collidable {
    boolean checkCollision(Collidable target);
    boolean visit(Collidable collidable);
    boolean accept(Circle circle);
    boolean accept(Line line);
}

public static class CollisionChecks {
    public static boolean check(Circle a, Circle b) { return false; }
    public static boolean check(Circle a, Line b) { return false; }
    public static boolean check(Line a, Line b) { return false; }
}

public class Line implements Collidable {
    @Override
    public boolean checkCollision(Collidable target) {
        return target.visit(this);
    }

    @Override
    public boolean visit(Collidable collidable) {
        return collidable.accept(this);
    }

    @Override
    public boolean accept(Circle circle) {
        return CollisionChecks.check(circle, this);
    }

    @Override
    public boolean accept(Line line) {
        return CollisionChecks.check(this, line);
    }

}

public class Circle implements Collidable {
    @Override
    public boolean checkCollision(Collidable target) {
        return target.visit(this);
    }

    @Override
    public boolean visit(Collidable collidable) {
        return collidable.accept(this);
    }

    @Override
    public boolean accept(Circle circle) {
        return CollisionChecks.check(this, circle);
    }

    @Override
    public boolean accept(Line line) {
        return CollisionChecks.check(this, line);
    }
}

10-04 13:56