寻求更好的设计,以便使用java进行多调度

时间:2013-04-19 20:17:50

标签: java design-patterns

在不支持多个调度的语言中,例如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(本); //访问者在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的最佳方法吗?

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

3 个答案:

答案 0 :(得分:1)

在您给出的示例中,您不需要两个接口,只需要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等)作为方法参数。因此它是糟糕的设计,为什么你甚至需要开始接口?看起来它不能在其他任何地方使用。

答案 1 :(得分:0)

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

正如我所看到的,真正的问题是你的Collidable界面应该有getNamegetType方法,它会返回“小行星”或“宇宙飞船”或者你有什么,然后你的collidesWith的实现可以简单地打印出自己的名字和碰撞伙伴的名字。我在这个例子中没有看到你需要双重发送 - 只是为什么instanceof是代码气味的情况。

答案 2 :(得分:0)

我希望我理解你的问题。

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

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编写的,如果有错字或眼睛伤害的格式,我会很抱歉。