试图实现访问者模式

时间:2011-12-13 00:07:59

标签: java design-patterns visitor

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

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

我很确定到目前为止我的代码是正确的,我只是想弄清楚如何传递用户读入的值。

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

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

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

对我来说,让访问者实际添加项目是有意义的,因为它是我想要特定于添加访问者的功能,但每次我尝试实现时我都会被告知我必须制作arraylist包含静态的菜单元素,我不禁想到我做错了。

我不是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());
    }
}

2 个答案:

答案 0 :(得分:2)

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

实际上,这打破了SRP =>单一责任原则因为添加和阅读是两个行为所以两个责任。要理解这一点,想象一下您现在决定从文件中读取菜单名称......您必须打开并重新编码“添加”访问者类。

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

因此在您的示例中,您应该尝试替换Console.readInt();和带有int方法参数和String方法参数的Console.readString()。

答案 1 :(得分:0)

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

  

“...

时使用访客模式      
      
  • 对象结构包含许多具有不同接口的对象类,并且您希望对依赖于其具体类的这些对象执行操作。

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

  •   
  • 定义对象结构的类很少更改,但您经常需要在结构上定义新操作。更改对象结构类需要重新定义所有访问者的界面,这可能是昂贵的。如果对象结构类经常更改,那么在这些类中定义操作可能更好。 ......“

  •   

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