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

Java访问者模式2
EN

Stack Overflow用户
提问于 2016-02-06 13:55:53
回答 2查看 412关注 0票数 2

下面是我用更好的代码示例问过的问题的后续问题:

下面的代码使用访问者模式:

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

输出为:

代码语言:javascript
复制
?
?
?
?

如果不在Animal.accept()中添加instanceof的开关,我如何修复它?(我不想在每次添加新的动物类时都维护switch() )

EN

回答 2

Stack Overflow用户

发布于 2016-02-06 14:06:09

我认为为抽象类(本例中为)实现一个动物访问方法是没有意义的。

在Visitor中,你总是知道所有可能的子类型。这是一种基本假设(否则您将向Visitor接口添加新方法)。但是您获得了动态实现不同行为的能力。在你的例子中,就是说话和行走。

要付出的代价是在每个具体类型中实现一个"accept“方法。您曾试图提供一个更通用的解决方案,但却弄糊涂了:)例如,查看Wikipedia描述。

他们在谈论汽车的不同部件,但想法是相同的:他们为所有部件实现了一个接受方法。

票数 6
EN

Stack Overflow用户

发布于 2016-02-10 19:25:30

正如在前面的回答中提到的,accept方法必须是抽象的,并在所有具体的子类型中实现。

现在,它们是您的实现中的两个额外问题:

  1. Dog类不是抽象的。这意味着如果您在Dog中提供了accept方法的默认实现,您将失去使用访问者模式的主要原因:您不能确保正确地处理了Dog.Return方法的所有子类型。
  2. Visitor方法“voidvoid:这将强制Visitor的所有实例通过副作用工作。你可能会发现corrected visitor pattern的error-prone.

要少得多

然后,访问者模式非常冗长,所以如果您想真正减少维护工作量,请考虑使用代码生成器(批注处理器)。我可以推荐其中的两个: adt4j (jdk7+)和derive4j (jdk8+)。这些生成器生成正确的子类和accept方法的实现。对于您的示例,使用derive4j并应用上面的两个“修复”,您可以这样写:

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

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

https://stackoverflow.com/questions/35237890

复制
相关文章

相似问题

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