繁体   English   中英

使用InstanceOf实现访客

[英]Implementing Visitor using InstanceOf

我做的访客模式很好。 但是,我想知道。

使用访问者模式的最重要动机是在客户端中添加涉及特定数据模型的逻辑,而无需检查实际数据对象类型。 用于求解的技术称为“双分派”。

因此,这里是实现accept()方法的数据模型的代码片段:

public class Ferrari extends Car {
    //......
    @Override
    public void accept(Visitor v){
      v.visit(this);
    }
  }

这里是实现Visitor接口的PrintCarVisitor

public class PrintCarVisitor implements Visitor {
  //...
  @Override
  public void visit(Ferrari c){
    System.out.println("Ferrari");
  }
}

因此,不需要if/else系列和instanceof系列。

任何客户将是:

Visitor visitor = new PrintCarVisitor();
car.accept(visitor);  //no need to know the exact Car's type

但是,由于Visitor不保留Open / Closed Principle(开放/封闭原则)(因为新的数据模型会通过添加其自己的visit方法来破坏类),所以为什么还要麻烦两次调度?

我们不能仅在访问者实现中隔离if/else系列。

使用这种假设的替代方法,这部分代码将消失:

 public class Ferrari extends Car {
    //This method is not needed anymore with this alternative
    @Override
    public void accept(Visitor v){
      v.visit(this);
    }
  }

PrintCarVisitor将是:

public class PrintCarVisitor {
   public void visit(Car c){
     if(c instanceof Ferrari){
       System.out.println("Ferrari");
     }
   }      
}

使用这种替代方法,每个调用者仍然可以像这样处理数据模型抽象:

new PrintCarVisitor().visit(car); //no need to know the exact data type in client side

先验地,第二种方法很棒,因为它不涉及纯访客模式实施期间生成的所有样板。

我想这种方法有两个缺点:

1)不能保证(如Visitor界面强加)任何使用过的访问者处置与当前处理的Car相对应的方法。

2)BoilerPlate代码通过一系列instanceofcasting变得更加沉重到Visitor实现类中。

它们是否还有其他缺点,以解释为什么访问者模式必须使用Double Dispatching,所以不能简单地将class的instanceof系列隔离在一个类中(例如静态Factory那样)?

  1. 如果这样做,您将不再有访客,那么您基本上将拥有某种处理器。 您的代码将只是列表迭代,每次循环时,您会将以前使用的accept传递给处理器,而该处理器是正式的访问者。 在某种意义上,您是在颠倒范式,而不是访问者访问被访问者。 被访问者成为访问者,因为它最初是传递给工作人员的。 你能做到这一点; 但您不会将其称为“访客”。

  2. 传统观点通常指示应将instanceof使用保留给最后手段。 当您可以让Java的多态性为您做到这一点时,为什么还要使用instanceof呢? 拥有对象的要点之一就是这种好处。 如果这样做,为什么不避开重写方法,而仅使用instanceof来确定在类的方法中要做什么,而不是依赖于动态分配(对于重写方法)?

Xtext项目存在相同的问题,他们创建了一个帮助器类PolymorphicDispatcher 简而言之, PolymorphicDispatcher在运行时会执行编译器在编译时所执行的操作:查找与一组参数最匹配的方法并调用它。

因此您的访客看起来像:

 public class PrintCarVisitor {
   public void visit(Car c){
      System.out.println("Just a car");
   }
   public void visit(Ferrari c){
      System.out.println("A Ferrari!");
   }
 }

这是来源。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM