首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >尝试实现访问者模式

尝试实现访问者模式
EN

Stack Overflow用户
提问于 2011-12-13 08:07:59
回答 2查看 926关注 0票数 4

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

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

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

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

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

或者我还没有走到让访问者实际添加元素的地步。例如,我是否只需要创建Menu元素,然后传递它,然后在Menu类中添加功能?

对我来说,让访问者实际添加项目是有意义的,因为这是我想要保留的特定于添加访问者的功能,但每次我尝试实现时,我总是被告知必须使包含菜单元素的arraylist成为静态的,我不禁认为我这样做是错误的。

我不是百分之百确定访问者模式对于我正在尝试做的事情是正确的?

就我个人而言,我相信我要么真的,真的很接近.否则就太离谱了!

你们能提供的任何帮助都是很棒的,即使你能给我一个好的教程来帮助我解释如何正确地使用这个模式。

这是我到目前为止所知道的:

代码语言:javascript
复制
interface MenuElementVisitor {
    void visit(Starter starter);
    void visit(MainCourse mainCourse);
    void visit(Desert desert);
    void visit(Drinks drinks);
    void visit(Menu menu);
}

菜单元素类

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

菜单类

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

访问者将项目添加到菜单中

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

访问者从菜单中删除项目

代码语言:javascript
复制
class MenuElementRemoveVisitor implements MenuElementVisitor {

}

运行代码演示

代码语言:javascript
复制
public class VisitorDemo {
    static public void main(String[] args) {
        Menu menu = new Menu();
        menu.accept(new MenuElementAddVisitor());
        menu.accept(new MenuElementRemoveVisitor());
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2011-12-26 04:02:15

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

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

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

因此,在您的示例中,您应该尝试将Console.readInt();和Console.readString()替换为一个整数方法参数和一个字符串方法参数。

票数 2
EN

Stack Overflow用户

发布于 2011-12-26 06:59:55

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

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

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

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

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

如果你真的想要一个类似的访问者模式,参见this answer。

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

https://stackoverflow.com/questions/8482734

复制
相关文章

相似问题

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