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