我很好地掌握了访问者模式。但是,我想知道一些事情。
使用访问者模式最重要的动机是在客户端添加涉及特定数据模型的逻辑,而无需检查真实的数据对象类型。用于求解的技术称为双重调度。
因此,这里是实现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 实现类中仍然较重,带有instanceof
和casting
。
他们是否有任何其他缺点解释了为什么访问者模式必须使用双重调度,因此不能简单地将instanceof
系列隔离在一个类中(例如静态Factory
)?