【问题标题】:Inherited enum redefinition继承的枚举重定义
【发布时间】:2012-10-06 19:07:44
【问题描述】:

它比听起来更复杂,但我认为我有义务尝试类似的东西。我想用枚举的原型制作一个抽象父类(我想用一个值声明枚举,这可能是默认的未初始化的值,并且还声明了我将从子类中使用的几个方法),然后我想要一个类来扩展抽象父级以实际初始化相同的枚举(我知道这实际上隐藏了父级枚举),以便孩子类将在枚举内定义一组项目,但可能保留这些方法。

我对这个抽象级别了解不多,所以我现在将描述我的问题的性质,以防有更实际的解决方案: 我有一堆文件,其中包含实现许多基于枚举的命令的类。 (例如,class1 实现 Observer 有一个更新方法,它使用基于枚举的开关来决定选择什么命令,这同样适用于其他类)我现在想以一种我有一个枚举变量的方式抽象整个事情所有类(例如 CommandSet)中的名称相同,这样我就可以在父级内部拥有一个通用方法,该方法能够使用枚举的内部方法将帮助列表打印到我的系统。现在我知道我可以在每个类中重写完全相同的方法,但我想抽象它以便其他人可以继续扩展我正在制作的库!

希望我不会太困惑或太困惑,​​有人可以帮助我! :)

编辑:这是代码的一个想法(可能不对):

  public abstract class Commands{
    enum CommandSet{ 
        // empty command, placeholder
        null_command ("command name", "command description");
        // the Strings used for name and description
        private final String name;
        private final String description;
        // constructor 
        CommandSet(String name, String description){
            this.name=name;
            this.description=description;
        }
        // get parameters
        public String getName(){
            return name;
        }
        public String getDescription(){
            return description;
        }
    }
    public void showHelp(){
        for (CommandSet i : CommandSet.values()) {
            printf(i.getName(),":",i.getDescription());
        }
    }
}

public class StandardCommads extends Commands implements Observer{
    // I want to change the enum here, just changing the values so that null_command ("command name", "command description") will get removed and I will add a dozen other values, but keep the methods that the parent had
    // update inherited from Observer
    @Override
    public void update(Observable observable, Object object) {
        // I want the commands inside the switch cases defined inside this class's enum 
        switch(CommandSet.valueOf(String.valueOf(object)){
            case command1: doStuff1();break;
            case command2: doStuff2();break;
            ...
            case commandN: doStuffN();break;
        }
    // other methods
    void doStuff1(){
        ...
    }
    ...
    void doStuffN(){
        ...
    }
}

public class NonStandardCommads extends Commands implements Observer{
    // Another set of commands here for the enum keeping the same methods it had in the parent

    // update inherited from Observer
    @Override
    public void update(Observable observable, Object object) {
        // Other set of commands inside this class used in the switch statement
        switch(CommandSet.valueOf(String.valueOf(object)){
            case Zcommand1: doStuffz1();break;
            case Zcommand2: doStuffz2();break;
            ...
            case ZcommandN: doStuffzN();break;
        }
    // other methods
    void doStuffz1(){
        ...
    }
    ...
    void doStuffzN(){
        ...
    }
}

【问题讨论】:

    标签: java enums


    【解决方案1】:

    不可能:Java 枚举既不能扩展另一个类,也不能扩展自身。

    但是,它们可以实现接口。也许你可以利用它来发挥你的优势。


    还有一些关于枚举的东西可以帮助你:枚举不是immutable。您可以更改枚举的字段值,但这会为整个 JVM 更改它们。

    另一种方法可能是将您的子类实例传递给枚举的方法,并让枚举将您的子类用作call back,以便为枚举的不同用户从枚举中获取不同的功能。

    【讨论】:

    • 不,我不是要扩展枚举,我的意思是第二个类将从抽象父级继承一个枚举。但是我可以部分重新定义它吗?
    • 所以你的意思是在枚举中实现一个接口,如enum Commands implements someInterface{ //codehere}
    • @Spiritios 没错。我很难回答你的问题:它似乎太啰嗦了。你能把它浓缩下来,让它更清晰吗?也许带有您希望代码外观的代码片段(即使语法无效),因此我们可以更好地了解您想要什么
    • 查看问题,我提供了一个我正在寻找的完整示例,并尽可能多地发表评论! :)
    【解决方案2】:

    不,你不能那样做。

    当您想在以后添加/扩展更多定义或实例化枚举实例时,Java 枚举非常快且肯定会耗尽燃料。 (例如从数据库加载它们,在实例方法中配置它们,而不仅仅是静态的。)

    Java 枚举中的行为/ 或逻辑也有点受限——您可以定义和设置属性,但只有静态可初始化的,并且逻辑看起来很基本(您最终主要只是将引用或序数与其他定义的枚举常量进行比较)。

    你可以做什么:

    可以使用整数代码实现祖先命令或抽象命令类,然后将其子类化以定义具体值/附加代码/加载或配置实例等。

    为了进一步的好处,您可以获得高效的切换和调度(通过代码)以及定义更多详细信息/属性、根据需要实例化命令等的能力。

    本质上,这就是在 Java 支持 Enum 之前定义枚举的方式。尽管您可能将它们用作值对象,而不是严格静态的。

    我的专长:

    我已经完成了大量的编译器和类型系统工作,尝试了文件类型和相关数据/行为的枚举。探索了外部限制,并达到了明确的界限。

    我也喜欢能够实例化并返回一个新的 UnknownFileType("") 作为答案。枚举无法做到这一点。

    示例:

    (我们将通过 String 而不是 int 发送——因为您的代码似乎使用的是 Java 7。这使得命令解析比同时需要语法“名称”和内部整数“代码”更容易。)

    public static class Command {
      protected String code;
      protected String desc;
      public String getCode() {return code;}
      public String getDesc() {return desc;}
      public Command (String code, String desc) {
        this.code = code;
        this.desc = desc;
      }
      public String toString() {return code;}
    }
    
    public class StandardCommands {
      public static Command READ = new Command("READ", "read a record");
      public static Command CREATE = new Command("WRITE", "create a record");
      public static Command EDIT = new Command("WRITE", "modify a record");
    }
    public class FurtherCommands extends StandardCommands {
      public static Command LIST = new Command("LIST", "list all records");
    }
    
    public class QueryCommands extends FurtherCommands {
      public static class QueryCmd extends Command {
        protected String search;
        public String getSearch() {return search;}
        // constructor..
      }
      public static QueryCmd QUERY_EXAMPLE = new QueryCmd("QUERY", "example", "query for specified string");
    
    
      public static QueryCmd createQuery (String search) {
        return new QueryCmd( "QUERY", search, "query for specified string");
      }
    }
    

    【讨论】:

    • 你能花点时间给我一个关于如何按照你的建议制作一个类似枚举的类的示例吗?可能是一个提示! :)
    • @Spiritios -- 我会很感激投票吗?我现在可能已经花了 20 分钟,试图传递我所知道的并回答你的问题 :) 谢谢!
    • 资源呢?就内存而言,这不是比枚举重得多吗? (所以,如果我有 20000 个命令的枚举,它们消耗的内存不会比这个类的 20000 个 OBJECTS 少得多吗?)
    • 没有什么不同,枚举也是一个对象。无论如何,Java 中的良好编程实践不再是试图避免高层的对象实例——许多 Command 实例可以是静态的,如上所示。静态时相当于枚举,非静态时更灵活。
    • 仍然让我在 switch 中使用代码为 String 时遇到麻烦,可能会将其转换为 int 来改进它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    相关资源
    最近更新 更多