[英]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代码通过一系列instanceof
和casting
变得更加沉重到Visitor实现类中。
它们是否还有其他缺点,以解释为什么访问者模式必须使用Double Dispatching,所以不能简单地将class的instanceof
系列隔离在一个类中(例如静态Factory
那样)?
如果这样做,您将不再有访客,那么您基本上将拥有某种处理器。 您的代码将只是列表迭代,每次循环时,您会将以前使用的accept
传递给处理器,而该处理器是正式的访问者。 在某种意义上,您是在颠倒范式,而不是访问者访问被访问者。 被访问者成为访问者,因为它最初是传递给工作人员的。 你能做到这一点; 但您不会将其称为“访客”。
传统观点通常指示应将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.