首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java访问者模式

Java访问者模式
EN

Stack Overflow用户
提问于 2016-02-05 17:22:28
回答 2查看 372关注 0票数 1

我尝试在扩展类中使用访问者模式。我有动物类的列表,每个类都是不同的动物。当我调用访问者时,它将只执行talk(Animal a),而不是对象的具体实例。如下所示:

代码语言:javascript
复制
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);
    }
}

输出为:

代码语言:javascript
复制
?
?
?

虽然我期望:

代码语言:javascript
复制
Meow
bark
Arf 

你知道如何在不把很多instanceof放在一个talk()方法中的情况下实现访问器吗?

EN

回答 2

Stack Overflow用户

发布于 2016-02-05 17:26:55

Visitor pattern的一个关键元素是double-dispatch:您需要从实际的子类中调用访问者方法

代码语言:javascript
复制
abstract class Animal {
  abstract void accept(Visitor v);
}

class Dog extends Animal {
  @Override void accept(Visitor v) { v.talk(this); }
}

// ... etc for other animals.

然后,将访问者传递给动物,而不是将动物传递给访问者:

代码语言:javascript
复制
for (Animal a : list)
  a.accept(visitor);

这样做的原因是编译器选择调用Visitor上的重载-它在运行时不会被选中。编译器只知道a是一个Animal,所以它知道可以安全调用的唯一方法就是Visitor.visit(Animal)重载。

票数 6
EN

Stack Overflow用户

发布于 2016-04-09 03:19:26

访问者模式基本上是一种多对多类行为解析机制。为了对你的动物例子有用/适用,我们需要添加一个访问者,正如Andy Turner所指出的那样。

加入“动物训练师”作为访客怎么样?不同的动物训练师可以让不同的动物说话不同(或不同)。

所以,首先,实体(动物接口)。我喜欢把它想象成一个“被演员扮演”的“事物”:

代码语言:javascript
复制
public interface IAnimal {

    public String getAnimalName();

    // aka...  public void accept(Visitor v)
    public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer);
}

然后让我们定义一个访问者类型(动物训练器接口)。我喜欢把访问者想象成一个作用于各种“事物”(实体)的“演员”:

代码语言:javascript
复制
public interface IAnimalTrainer {

    public String getTrainerName();

    //aka... public void visit(Dog dog);
    public void animalTrainerMakesAnimalSpeak(Dog dog);
    public void animalTrainerMakesAnimalSpeak(Cat cat);
    public void animalTrainerMakesAnimalSpeak(Poodle poodle);
}

现在让我们创建动物(实现IAnimal接口):

猫:

代码语言:javascript
复制
public class Cat implements IAnimal {

    private String animalName;

    @Override
    public String getAnimalName() {
        return animalName;
    }
    public void setAnimalName(String animalName) {
        this.animalName = animalName;
    }

    public Cat(String animalName) {
        this.animalName = animalName;
    }
    public Cat() {
        // Default constructor
    }

    @Override
    public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer) {
        animalTrainer.animalTrainerMakesAnimalSpeak(this);
    }
}

狗:

代码语言:javascript
复制
public class Dog implements IAnimal {

    private String animalName;

    @Override
    public String getAnimalName() {
        return animalName;
    }
    public void setAnimalName(String animalName) {
        this.animalName = animalName;
    }

    public Dog(String animalName) {
        this.animalName = animalName;
    }
    public Dog() {
        // Default constructor
    }

    @Override
    public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer) {
        animalTrainer.animalTrainerMakesAnimalSpeak(this);
    }
}

贵宾犬:

代码语言:javascript
复制
public class Poodle extends Dog {

    public Poodle(String animalName) {
        super(animalName);
    }
    public Poodle() {
        super();
    }

    @Override
    public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer) {
        animalTrainer.animalTrainerMakesAnimalSpeak(this);
    }
}

现在让我们创建动物训练师,菲尔和杰克(实现IAnimalTrainer接口):

动物训练师菲尔:

代码语言:javascript
复制
public class AnimalTrainerPhil implements IAnimalTrainer {

    private String trainerName = "Phil";

    @Override
    public String getTrainerName() {
        return trainerName;
    }
    public void setTrainerName(String trainerName) {
        this.trainerName = trainerName;
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Dog dog) {
        System.out.println(
                "Animal trainer " 
                + getTrainerName()
                + " gets " 
                + dog.getAnimalName() 
                + " the dog to say: BARK!!");
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Cat cat) {
        System.out.println(
                "Animal trainer "
                + getTrainerName()
                + " gets " 
                + cat.getAnimalName() 
                + " the cat to say: MEOW!!");
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Poodle poodle) {
        animalTrainerMakesAnimalSpeak((Dog)poodle);
    }
}

动物训练师杰克:

代码语言:javascript
复制
public class AnimalTrainerJack implements IAnimalTrainer {

    private String trainerName = "Jack";

    @Override
    public String getTrainerName() {
        return trainerName;
    }
    public void setTrainerName(String trainerName) {
        this.trainerName = trainerName;
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Dog dog) {
        System.out.println(
                "Animal trainer " 
                + getTrainerName()
                + " gets " 
                + dog.getAnimalName() 
                + " the dog to say: Bark bark.");
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Cat cat) {
        System.out.println(
                "Animal trainer " 
                + getTrainerName()
                + " gets " 
                + cat.getAnimalName() 
                + " the cat to say: Meoooow.");
    }

    @Override
    public void animalTrainerMakesAnimalSpeak(Poodle poodle) {
        System.out.println(
                "Animal trainer " 
                + getTrainerName()
                + " gets " 
                + poodle.getAnimalName() 
                + " the poodle to say: Yip! Yip!");
    }
}

现在,让所有的动物训练师(Phil和Jack)通过一个Manager类让所有的动物(猫、狗、贵宾犬)都能说话:

代码语言:javascript
复制
public class ManagerOfAnimalTrainersAndAnimals {

    public static void main(String[] args) {

        ArrayList<IAnimal> allAnimals = new ArrayList<>();
        allAnimals.add(new Dog("Henry"));
        allAnimals.add(new Cat("Priscilla"));
        allAnimals.add(new Poodle("Spike"));

        ArrayList<IAnimalTrainer> allAnimalTrainers = new ArrayList<>();
        allAnimalTrainers.add(new AnimalTrainerPhil());
        allAnimalTrainers.add(new AnimalTrainerJack());

        // Allow all animal trainers to get each animal to speak
        for (IAnimalTrainer animalTrainer : allAnimalTrainers) {
            for (IAnimal animal : allAnimals) {
                animal.allowAnimalTrainerToMakeMeSpeak(animalTrainer);
            }
        }
    }
}

下面是输出:

代码语言:javascript
复制
Animal trainer Phil gets Henry the dog to say: BARK!! 
Animal trainer Phil gets Priscilla the cat to say: MEOW!! 
Animal trainer Phil gets Spike the dog to say: BARK!! 
Animal trainer Jack gets Henry the dog to say: Bark bark. 
Animal trainer Jack gets Priscilla the cat to say: Meoooow. 
Animal trainer Jack gets Spike the poodle to say: Yip! Yip!

这使得添加新的训练师相对容易,他们可以访问动物类型的特定内容(例如,如果您将爪子信息添加到猫,将爪子信息添加到狗,……)当它们作用于各种动物时。我认为传统的“访问者”示例的问题在于它太模糊,不够具体。出租车的例子也不适合我。我希望这个例子能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35220362

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档