2011-12-13 67 views
4

我试图去掌握Java中的访问者方法。试图实现访问者模式

我想写一个非常简单的程序来适应它。基本上它是一个食物菜单。我想读取用户输入(食物类型(起动器,主菜...)和食物(面食,鱼...)的名称),然后将此项目添加到菜单中。

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

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

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

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

对我来说,让访问者真正添加项目是有意义的,因为它是我想保持特定于添加访问者的功能,但是每次我尝试实现时,都会被告知我必须使包含菜单元素静态的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); 
    } 
} 

Menu类

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

该死的!我忘了在昨天晚上(我发布帖子的时候很晚了,我现在要扔掉我现在的代码) – Ian

回答

2

我认为你的“并称”不访问者应该知道你使用命令行参数的事实以表明你的菜单名称。

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

您应该拥有一个主要的泛型类,他们只知道String(用于名称)和专门的类,他们可以创建或最终使用您的参数提供的精确位置。因此在你的例子中,你应该尝试替换Console.readInt();和Console.readString()与一个int方法参数和一个String方法参数。

+0

根据我的说法,在一个已经创建的对象上,而不是添加它...我会用一个静态方法来替换您的MenuElementAddVisitor Factory,其中包含一个String和一个Int参数,例如。 – Mik378

+0

对不起,但你的评论很不清楚。编写一个处理对象层次结构的访问者并将其他对象添加到其他对象中没有任何问题。事实上,我们甚至不知道OP的意图是什么,因为他的访问者课程不完整。 –

0

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

“......当

  • 对象结构包含很多类对象的具有不同接口的使用访问者模式,你想对这些对象依赖于执行操作它们的具体类

  • 需要在对象结构中的对象上执行许多独特和不相关的操作,并且希望避免使用这些操作“污染”它们的类。在一个类中定义它们。当对象结构被许多应用程序共享时,使用Visitor将操作放在那些需要它们的应用程序中。

  • 定义对象结构的类几乎不会改变,但您通常希望在结构上定义新的操作。更改对象结构类需要重新定义所有访问者的接口,这可能是昂贵的。如果对象结构类经常变化,那么定义这些类中的操作可能会更好。 ......”

如果你真的想类似的东西,一个访问者模式看this答案。