用反射构建基于文本的菜单

时间:2011-12-03 18:45:11

标签: java reflection menu

我正在使用JosAH's text-based menu system的修改版本,并试图弄清楚如何使用反射来创建类声明的子类中的项列表。因为不同的菜单项使用不同的参数来操作底层数据,所以我在实现它们的实例化时遇到了问题。

例如,分配是创建自定义链接列表,因此菜单选项包含PrintInsertSaveQuit等。 insert只需要对链表进行引用,以便解析输入并调用链表中的相应函数。 Save还需要保存文件,而Quit不需要任何其他参数。

public class MenuList extends TextMenu { //TextMenu extends MenuItem
    List<MenuItem> items;

    public MenuList (Object data, File file) {} //calls fillList

    //calls createList which fills a List<MenuItem> and copies it to this.items
    protected void fillList(Object data, File file) {
        this.items.addAll( createList(this.getClass(), ... args?) );
    }

    private static class MenuQuit extends MenuItem {
        public MenuQuit() {} //does not need data
    }

    private static class MenuOne extends MenuItem {
        public MenuOne(Object data) {} //manipulates data
    }

    private static class MenuTwo extends MenuItem {
        public MenuOne(Object data) {} //also manipulates data
    }

    private static class MenuThree extends MenuItem {
        //manipulates data and saves to file
        public MenuThree(Object data, File file) {} 
    }

    private static class NestedMenu extends MenuList {
        //needs parameters to pass to it's own menuItems
        public NestedMenu(Object data, File file) {}    
    }
}

public static List<MenuItem> createList(Class cls, ...args? ) {
    List<MenuItem> items = new ArrayList<MenuItem>();
    try {
        Classes<?>[] param = { parse(args)? };
        Class<?>[] menuList = cls.getDeclaredClasses();

        for(Class<?> c : menuList) {
            if(MenuItem.class.isAssignableFrom(c)) {//only adding the MenuItems
                Constructor<?> ct = c.getConstructor(param);
                Object menuItem = ct.newInstance( ...args? );
                items.add( (MenuItem) menuItem );
            }
        }
    } catch (Exception e) { }
}

有没有办法推广createList,以便使用必要的参数创建菜单项?

另外,由于我在这方面工作了多长时间,我完全接受这种完全过度设计的解决方案的可能性,并且我应该废弃这个想法的大部分或全部。< / p>

编辑:我不知道这是否是添加此项信息的最佳位置 - 这是我一直在考虑的解决方案,在阅读了一些回复和评论之后,它可能是正确的。如果MenuItem始终接受单个Object作为参数,我可以在调用getConstructornewInstance时做出此假设。之后,我将把它留给特定的类来将Object转换为有用的东西,以便从中获取数据。

public class MenuItem {
    Object data;
    public MenuItem(Object data) {
        this.data = data;
        parseData();
    }
    protected abstract void parseData();
}

private static class MenuQuit extends MenuItem {
    public MenuQuit(Object data) { super(data) } //nothing additional needed
    protected void parseData() {} //does nothing
}

private static class MenuSave extends MenuItem { //as outlined above
    private CustomLinkedList list;
    private File saveFile;
    public MenuSave(Object data) {
        super(data);
    }

    //may be able to use reflection to generalize this
    protected void parseData() { 
        this.list = ((MyCustomData) data).list;
        this.saveFile = ((MyCustomData) data).saveFile;
    }
}

public class MyCustomData {
    public CustomLinkedList list;
    public File saveFile;
    public int otherData;
    public MyCustomData(CustomLinkedList a, File b, int c) {} //assignment
}

我试图避免使用这种方法,因为它开始为子类MenuItems添加复杂性,我希望尽可能简单。有没有办法改进这个解决方案?

2 个答案:

答案 0 :(得分:0)

不完全是答案,
但由于我一般不是反思的忠实粉丝,这是另一个想法:

您可以将datafile添加到基类MenuItem,并将null保留在不适用的位置。

答案 1 :(得分:0)

嗯。如果您在不需要数据的案例中有参数而忽略它们会发生什么?