【发布时间】:2012-12-17 13:04:16
【问题描述】:
我很好掌握访客模式。 但是,我想知道一些事情。
使用访问者模式最重要的动机是在客户端添加涉及特定数据模型的逻辑,而无需检查真实的数据对象类型。用于求解的技术称为 Double-Dispatching。
所以,这里是实现accept() 方法的数据模型的代码sn-p:
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 代码在带有instanceof 和casting 系列的Visitor 实现类中仍然较重。
它们是否还有其他缺点来解释为什么访问者模式必须使用双重调度,因此不能简单地将 instanceof 系列隔离在一个类中(例如静态 Factory 所做的那样)?
【问题讨论】:
标签: java design-patterns visitor-pattern open-closed-principle