下面是我用更好的代码示例问过的问题的后续问题:
下面的代码使用访问者模式:
class Animal { void accept(Visitor v) { v.visit(this); } }
class Cat extends Animal {}
class Dog extends Animal {}
class Poodle extends Dog {}
interface Visitor {
public void visit(Animal a);
public void visit(Cat a);
public void visit(Dog a);
public void visit(Poodle a);
}
class TalkVisitor implements Visitor {
public void visit(Animal a) { System.out.println("?"); }
public void visit(Cat a) { System.out.println("Meow"); }
public void visit(Dog a) { System.out.println("bark"); }
public void visit(Poodle a) { System.out.println("Arf"); }
}
class WalkVisitor implements Visitor {
public void visit(Animal a) { System.out.println("?"); }
public void visit(Cat a) { System.out.println("Sneak"); }
public void visit(Dog a) { System.out.println("Walk"); }
public void visit(Poodle a) { System.out.println("Skip"); }
}
public class Demo{
public static void main(String []args){
Animal list[] = { new Cat(), new Dog(), new Poodle() };
for (Animal a : list)
a.accept(new TalkVisitor());
for (Animal a : list)
a.accept(new WalkVisitor());
}
} 输出为:
?
?
?
?如果不在Animal.accept()中添加instanceof的开关,我如何修复它?(我不想在每次添加新的动物类时都维护switch() )
发布于 2016-02-06 14:06:09
我认为为抽象类(本例中为)实现一个动物访问方法是没有意义的。
在Visitor中,你总是知道所有可能的子类型。这是一种基本假设(否则您将向Visitor接口添加新方法)。但是您获得了动态实现不同行为的能力。在你的例子中,就是说话和行走。
要付出的代价是在每个具体类型中实现一个"accept“方法。您曾试图提供一个更通用的解决方案,但却弄糊涂了:)例如,查看Wikipedia描述。
他们在谈论汽车的不同部件,但想法是相同的:他们为所有部件实现了一个接受方法。
发布于 2016-02-10 19:25:30
正如在前面的回答中提到的,accept方法必须是抽象的,并在所有具体的子类型中实现。
现在,它们是您的实现中的两个额外问题:
Dog类不是抽象的。这意味着如果您在Dog中提供了accept方法的默认实现,您将失去使用访问者模式的主要原因:您不能确保正确地处理了Dog.Return方法的所有子类型。Visitor方法“void”void:这将强制Visitor的所有实例通过副作用工作。你可能会发现corrected visitor pattern的error-prone.要少得多
然后,访问者模式非常冗长,所以如果您想真正减少维护工作量,请考虑使用代码生成器(批注处理器)。我可以推荐其中的两个: adt4j (jdk7+)和derive4j (jdk8+)。这些生成器生成正确的子类和accept方法的实现。对于您的示例,使用derive4j并应用上面的两个“修复”,您可以这样写:
import static Animals.*;
import static Dogs.*;
import java.util.Arrays;
import java.util.function.Function;
class Cat {}
@org.derive4j.Data
abstract class Dog {
interface Visitor<R> {
R Terrier(String name);
R Poodle(String name);
}
abstract <R> R accept(Visitor<R> visitor);
}
@org.derive4j.Data
abstract class Animal {
interface Visitor<R> {
R cat(Cat cat);
R dog(Dog dog);
}
abstract <R> R accept(Visitor<R> visitor);
public static void main(String[] args) {
final Function<Animal, String> talkVisitor = Animals.cases()
.cat("Meow")
.dog(Dogs.cases()
.Poodle("Arf")
.otherwise("bark"));
final Function<Animal, String> walkVisitor = Animals.cases()
.cat("Sneak")
.dog(Dogs.cases()
.Poodle("Skip")
.otherwise("Walk"));
Animal[] list = { cat(new Cat()), dog(Terrier("Max")), dog(Poodle("Minus")) };
for (Animal a : list)
System.out.println(talkVisitor.apply(a));
for (Animal a : list)
System.out.println(walkVisitor.apply(a));
// or better:
Arrays.asList(list).stream()
.map(talkVisitor)
.forEach(System.out::println);
}
}https://stackoverflow.com/questions/35237890
复制相似问题