寻求更好的设计与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(); }
然后Spaceship
, Plane
和Asteroid
都会实现collideWith
和getType
。 作为一个示例实现,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
界面设计很差。 接口的目的是定义实现该接口的所有类必须提供方法定义(实现)的方法。 但是你的界面非常具体:它提供了几种类型( Spaceship
, Asteroid
等)作为方法参数。 因此它是糟糕的设计,为什么你甚至需要开始接口? 看起来它不能在其他任何地方使用。
双重调度与方法重载有关。 您在代码片段中显示的内容仅依赖于单个调度 – 您有一个接口,其实现将在运行时调用。
正如我所看到的,真正的问题是你的Collidable
接口应该有一个getName
或getType
方法,它返回“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编写的,如果有错字或眼睛受伤的格式,我会很抱歉。