我尝试使用扩展类的访问者模式。我有动物类列表,每个动物都是不同的。当我给访问者打电话时,它只执行谈话(动物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()方法的情况下实现访问者吗?
答案 0 :(得分:6)
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)
重载。
答案 1 :(得分:0)
访问者模式基本上是一个多对多的类行为解析机制。为了对您的动物实例有用/适用,我们需要添加访问者,正如Andy Turner所说。
如何包括"动物训练师"作为访客?不同的动物训练师可以让不同的动物以不同的方式说话(或不是)。
所以,首先,实体(动物界面)。我喜欢将此视为" Thing"被演员"
采取行动public interface IAnimal {
public String getAnimalName();
// aka... public void accept(Visitor v)
public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer);
}
然后让我们定义一个访客类型(动物训练师界面)。我喜欢把访客想象成一个"演员"采取行动的各种事情" (实体):
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接口):
猫:
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);
}
}
犬:
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);
}
}
贵宾犬:
public class Poodle extends Dog {
public Poodle(String animalName) {
super(animalName);
}
public Poodle() {
super();
}
@Override
public void allowAnimalTrainerToMakeMeSpeak(IAnimalTrainer animalTrainer) {
animalTrainer.animalTrainerMakesAnimalSpeak(this);
}
}
现在让我们创建动物训练师Phil和Jack(实现IAnimalTrainer接口):
动物训练师菲尔:
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);
}
}
动物训练师杰克:
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!");
}
}
现在让我们把这一切都拉到一起,让所有动物训练师(菲尔和杰克)通过经理课程让所有的动物(猫,狗,贵宾犬)说话:
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);
}
}
}
}
这是输出:
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!
这样可以相对轻松地添加能够访问动物类特定事物的新训练师(例如,如果您向猫添加爪信息,并向爪子添加爪子信息......),因为它们会对各种动物起作用。我认为传统&#34;访客&#34;例如,它太模糊,不够具体。出租车的例子对我来说也没办法。我希望这个例子有所帮助。