2011-12-03 27 views
0

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

举例来说,任务是创建一个自定义链接列表,因此菜单选项将包括PrintInsertSaveQuit等印刷和插入只是为了分析输入需要对链接列表的引用并在链接列表中调用相应的函数。 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,以便菜单项创建必要的参数?另外,由于我在这方面工作了多长时间,因此我完全接受这种可能性,即这是一个完全过度工程的解决方案,我应该删除这个想法的大部分,或者可能是全部。

编辑:我不知道这是否是添加此信息 - 这是一个解决方案,我就一直在想最好的地方,并通过一些回应和评论看完之后,它可能是正确的。如果MenuItem总是接受单个对象作为参数,那么我可以在拨打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,我希望能保持尽可能简单。有没有办法改进这个解决方案?

回答

0

不完全是一个答案,
但因为我通常不喜欢这里反射的大风扇是另一种思路:

您可以添加datafile到你的基类MenuItem,让他们null他们在哪里不适用。

+0

我曾经想过,但数据和文件只是例子。我后来可能会有MenuItem需要各种其他参数,我不太喜欢让MenuItem依赖于它的子类。 – pLiKT

+0

一些框架提供了一个通用的(不是Java的意义上的)'Object',它可以保存你的回调函数所需的数据。那个怎么样? – DerMike

+0

我发布的解决方案类似于您所提及的@DerMike原始问题吗? – pLiKT

0

嗯。如果您在不需要数据并且忽略它们的情况下有争论,会发生什么?