2

我很好地掌握了访问者模式。但是,我想知道一些事情。

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

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

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

这里是一个PrintCarVisitor实现Visitor接口:

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

但是,既然访问者没有保持开/关原则(因为一个新的数据模型会导致通过添加自己的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 代码在 Visitor 实现类中仍然较重,带有instanceofcasting

他们是否有任何其他缺点解释了为什么访问者模式必须使用双重调度,因此不能简单地将instanceof系列隔离在一个类中(例如静态Factory)?

4

2 回答 2

4
  1. 如果你这样做,你就不再有访客,你基本上有某种处理器。您的代码将只是一个列表迭代,每次通过循环时,您都会将以前使用的内容传递accept给处理器,即正式的访问者。从某种意义上说,您不是在访问被访问者,而是在颠倒范式。访问者成为访问者,因为它最初被传递给工作人员。你可以做到这一点; 你不会称它为访客。

  2. 传统智慧通常规定instanceof应将使用保留为最后的手段。instanceof当你可以让Java的多态性为你做这件事时,你为什么要使用?拥有对象的要点之一就是这种好处。如果你这样做了,为什么不避开覆盖方法,而只使用instanceof来确定在类的方法中做什么,而不是依赖于动态调度,对于覆盖方法的情况?

于 2012-12-17T13:16:01.450 回答
1

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!");
   }
 }

这是来源。

于 2012-12-17T13:17:17.310 回答