寻求更好的设计与java进行多调度

在不支持多个调度的语言(例如Java)中,代码可能看起来像这样

/* Example using run time type comparison via Java's "instanceof" operator */ interface Collideable { void collideWith(Collideable other); } class Asteroid implements Collideable { public void collideWith(Collideable other) { if (other instanceof Asteroid) { System.out.println("AAAAAA"); } else if (other instanceof Spaceship) { System.out.println("BBBBBB"); } else if (other instanceof Plane) { System.out.println("CCCCCCC"); } } } class Spaceship implements Collideable { public void collideWith(Collideable other) { if (other instanceof Asteroid) { System.out.println("DDDDDDD"); } else if (other instanceof Spaceship) { System.out.println("EEEEEEE"); } else if (other instanceof Plane) { System.out.println("FFFFFFF"); } } } class Plane implements Collideable { public void collideWith(Collideable other) { if (other instanceof Asteroid) { System.out.println("GGGGGGG"); }else if (other instanceof Spaceship) { System.out.println("HHHHHHH"); }else if (other instanceof Plane) { System.out.println("KKKKKK"); } } } 

由于访问者模式可以帮助解决这个问题,我在想是否应该使用void collideWith(){visitor.visit(this); //访问者在setter中设置}

 interface Visitor { void visit(Collideable c); void visit(Asteroid c); void visit(Spaceship c); void visit(Plane c); } 

那么每个独特的println应该在访问者的子类中实现如下?

 class AsteroidVisitor implements Visitor { void visit(Collideable c) {} void visit(Asteroid c) { System.out.println("AAAAAA"); } void visit(Spaceship c) { System.out.println("BBBBBBB"); } void visit(Plane c) { System.out.println("CCCCCC"); } } //etc for SpaceshipVisitor and PlaneVisitor() 

这是处理这种重构以替换instanceof的最佳方法吗?

编辑:打印输出只是每种方法中独特操作的一个例子,而不是最终结果。 我修改我的例子是清楚的。

在您给出的示例中,您不需要两个只需要Collideable接口的接口。 Collideable接口可以定义如下:

 interface Collideable { void collideWith(Collideable other); String getType(); } 

然后SpaceshipPlaneAsteroid都会实现collideWithgetType 。 作为一个示例实现,Spaceship的实现将如下所示:

 class Spaceship implements Collideable { public void collideWith(Collideable other) { System.out.println(this.getType() + " collides with " + other.getType()); } public String getType(){ return "Spaceship"; } } 

您可以更进一步,将Collideable声明为抽象类,提供collideWith的实现,因为它始终是相同的。 例如:

 abstract class Collideable { void collideWith(Collideable other){ System.out.println(this.getType() + " collides with " + other.getType()); } String getType(); } 

作为旁注和一般提示,您的Visitor界面设计很差。 接口的目的是定义实现该接口的所有类必须提供方法定义(实现)的方法。 但是你的界面非常具体:它提供了几种类型( SpaceshipAsteroid等)作为方法参数。 因此它是糟糕的设计,为什么你甚至需要开始接口? 看起来它不能在其他任何地方使用。

双重调度与方法重载有关。 您在代码片段中显示的内容仅依赖于单个调度 – 您有一个接口,其实现将在运行时调用。

正如我所看到的,真正的问题是你的Collidable接口应该有一个getNamegetType方法,它返回“asteroid”或“spaceship”或者你有什么,然后你的collidesWith实现可以简单地打印出自己的名字和它的碰撞伙伴的名字。 我没有在这个例子中看到你需要双重调度 – 只是为什么instanceof是代码气味的情况。

我希望我理解你的问题。

您可以考虑添加一个方法,例如:

 interface Collideable { void collideWith(Collideable other); //new method String getSpecificStuff(); } class Asteroid implements Collideable { String getSpecificStuff(){ return "Asteroid"; } } 

然后方法:

  public void collideWith(Collideable other) { System.out.println(this.getSpecificStuff() +" VS " + other.getSpecificStuff()); } 

其他子类只遵循上面的规则。

当然,这些只是一些例子。 您可以使用真实逻辑实现自己的getSpecificStuff()方法。

代码不是用IDE编写的,如果有错字或眼睛受伤的格式,我会很抱歉。