Java 访问者模式

标签 java visitor-pattern

我尝试将访问者模式与扩展类一起使用。我有动物类列表,每个都是不同的动物。当我调用访问者时,它将只执行 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/

相关文章:

java - 使用 JDT 的 AST 识别传递给方法的参数类型

C++ 避免向下转型或变体

java - 无法获取提供程序 androidx.core.content.FileProvider : java. lang.IllegalArgumentException : Missing android. support.FILE_PROVIDER_PATHS 元数据?

JavaFX:在 onEditCommit 函数中使用 ListView.edit(int itemIndex)

java - 如何模拟对象构造?

python - 访客模式,为什么有用?

java - 访问者模式中 `accept` 方法需要什么

java - 多态性和基于实例的switch case

java - VLCJ RTP 流客户端

java - 使用Java将图像上传到MySql数据库