【问题标题】:Trying to implement the Visitor pattern尝试实现访问者模式
【发布时间】:2011-12-13 00:07:58
【问题描述】:

我正在尝试掌握 Java 中的访问者方法。

我正在尝试编写一个非常简单的程序来习惯它。基本上它是一个食物菜单。我想读入用户输入(食物类型(开胃菜、主菜……)和食物名称(意大利面、鱼……)),然后将此项目添加到菜单中。

我相当确定到目前为止我的代码是正确的,我只是在努力弄清楚如何传递从用户那里读取的值。

我的一个也是程序员的朋友告诉我,您应该在访问者类中拥有所有功能(或至少尽可能多)。

那么我是否将用户输入创建到菜单元素中?然后让访问者将元素添加到菜单中? (我也希望能够从菜单中删除项目,但我假设这只是逆向工程添加的方法)

或者我没有让访问者实际添加元素。例如;我是否只需创建菜单元素然后传递它,然后在菜单类中添加功能?

对我来说,让访问者实际添加项目是有意义的,因为我想保留特定于添加访问者的功能,但每次我尝试实现时,我都会被告知我必须创建数组列表包含静态菜单元素,我不禁认为我做错了。

我不能 100% 确定访客模式是否适合我正在尝试做的事情?

就我个人而言,我相信我要么真的,真的很接近......要么很远!!

你们能提供的任何帮助都会很棒,即使你们可以向我指出一个很好的教程来帮助解释如何正确使用这种模式。

这是我目前所拥有的:

interface MenuElementVisitor {
    void visit(Starter starter);
    void visit(MainCourse mainCourse);
    void visit(Desert desert);
    void visit(Drinks drinks);
    void visit(Menu menu);
}

菜单元素类

interface MenuElement {
    void accept(MenuElementVisitor visitor); // MenuElements have to provide accept().
}

class Starter implements MenuElement {
    private String name;

    public Starter(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void accept(MenuElementVisitor visitor) {
        visitor.visit(this);
    }
}

class MainCourse implements MenuElement {
    private String name;

    public MainCourse(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void accept(MenuElementVisitor visitor) {
        visitor.visit(this);
    }
}

class Desert implements MenuElement {
    private String name;

    public Desert(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void accept(MenuElementVisitor visitor) {
        visitor.visit(this);
    }
}

class Drinks implements MenuElement {
    private String name;

    public Drinks(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public void accept(MenuElementVisitor visitor) {
        visitor.visit(this);
    }
}

菜单类

class Menu implements MenuElement {
    MenuElement[] elements;

    public MenuElement[] getElements() {
        return elements.clone(); // Return a copy of the array of references.
    }

    public Menu() {
        this.elements = new MenuElement[] {     
            new Starter("Soup"), 
            new Starter("Pate"),
            new MainCourse("Steak"), 
            new MainCourse("Fish"),
            new Desert("Ice Cream"), 
            new Desert("Apple Tart"),
            new Drinks("7up"),
            new Drinks("Wine"),
        };
    }

    public void accept(MenuElementVisitor visitor) {   
        for(MenuElement element : this.getElements()) {
            element.accept(visitor);
        }
        visitor.visit(this);       
    }
}

向菜单添加项目的访问者

class MenuElementAddVisitor implements MenuElementVisitor {
    System.out.println("Press 1 for Starter, 2 for Main Course, 3 for Desert or 4 for Drinks");
    int MenuElementType = Console.readInt();
    System.out.println("Type the name of the Menu Element you want to add");
    String MenuElementName = Console.readString();

访问者从菜单中删除项目

class MenuElementRemoveVisitor implements MenuElementVisitor {

}

运行代码演示

public class VisitorDemo {
    static public void main(String[] args) {
        Menu menu = new Menu();
        menu.accept(new MenuElementAddVisitor());
        menu.accept(new MenuElementRemoveVisitor());
    }
}

【问题讨论】:

  • 看起来你的两个访问者类都没有进入。访问方法都没有,第二个是空的。
  • 该死!昨晚忘记放了(发帖的时候已经很晚了,我现在把我现在的代码扔进去)

标签: java design-patterns visitor-pattern


【解决方案1】:

我认为您的“添加”访问者不应该知道您使用命令行参数来指示菜单名称这一事实。

确实,这违反了 SRP => 单一职责原则,因为添加和读取是两个动作,因此是两个职责。要理解这一点,假设您现在决定从文件中读取菜单名称……您必须打开并重新编码您的“添加”访问者类。

你应该有一个主要的泛型类,他只知道 String(对于名称)和专门的类,有人可以创建或最终使用你的类,以精确地从提供参数的位置。

所以在你的例子中,你应该尝试替换 Console.readInt();以及带有 int 方法参数和 String 方法参数的 Console.readString()。

【讨论】:

  • 据我说,访问者适用于已创建的对象,而不是添加它...我会用静态方法 Factory 替换您的 MenuElementAddVisitor,例如参数为 String 和 Int。
  • 抱歉,您的评论很不清楚。编写处理对象层次结构的访问者并向其他对象添加内容并没有错。事实上,我们甚至不知道 OP 的意图是什么,因为他的访问者类不完整......
【解决方案2】:

在这种情况下,您可能不需要访客。 gang-of-four 说:

" ... 在以下情况下使用访问者模式

  • 一个对象结构包含许多具有不同接口的对象类,您希望对这些对象执行依赖于其具体类的操作。

  • 需要对对象结构中的对象执行许多不同且不相关的操作,并且您希望避免这些操作“污染”它们的类。访问者允许您通过将相关操作定义在一个类中来将它们保持在一起。当对象结构被许多应用程序共享时,使用访问者将操作放在需要它们的应用程序中。

  • 定义对象结构的类很少更改,但您经常希望在该结构上定义新操作。更改对象结构类需要重新定义所有访问者的接口,这可能是昂贵的。如果对象结构类经常更改,那么最好在这些类中定义操作。 ……”

如果您真的想要类似的访问者模式,请参阅this 答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    • 1970-01-01
    • 1970-01-01
    • 2017-09-17
    相关资源
    最近更新 更多