我尝试将访问者模式与扩展类一起使用。我有动物类列表,每个都是不同的动物。当我调用访问者时,它将只执行 talk(Animal a) 而不是对象的具体实例。见下文:
class Animal {}
class Cat extends Animal {}
class Dog extends Animal {}
class Poodle extends Dog {}
class Visitor {
public void talk(Animal a) { System.out.println("?"); }
public void talk(Cat a) { System.out.println("Meow"); }
public void talk(Dog a) { System.out.println("bark"); }
public void talk(Poodle a) { System.out.println("Arf"); }
}
public class Demo{
public static void main(String []args){
Visitor visitor = new Visitor();
Animal list[] = { new Cat(), new Dog(), new Poodle() };
for (Animal a : list)
visitor.talk(a);
}
}
输出是:
?
?
?
虽然我期望:
Meow
bark
Arf
知道如何在不将许多 instanceof 放入单个 talk() 方法中的情况下实现访问者吗?
最佳答案
Visitor pattern 的关键要素是double-dispatch : 您需要从实际的子类调用访问者方法:
abstract class Animal {
abstract void accept(Visitor v);
}
class Dog extends Animal {
@Override void accept(Visitor v) { v.talk(this); }
}
// ... etc for other animals.
然后,您将访问者传递给动物,而不是将动物传递给访问者:
for (Animal a : list)
a.accept(visitor);
原因是编译器选择调用Visitor
上的重载——它不是在运行时选择的。编译器只知道 a
是一个 Animal
,因此它知道可以安全调用的唯一方法是 Visitor.visit(Animal)
过载。
关于Java 访问者模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35220362/