如何从抽象类扩展枚举类?

时间:2013-03-16 15:12:34

标签: java

有这样的事情:

public enum Token
{
     FOO("foo", "f"),
     QUIT("quit", "q"),
     UNKNOWN("", "");
     ...

     public parse(String s) {
         for (Token token : values()) {
              ...
              return token;
         }
         return UNKNOWN;
     }
}

抽象类:

abstract class Base 
{
    private boolean run;

    Base() {
        run = true;

        while (run) {
             inp = getInput();
             act(inp);
        }
    }

    public boolean act(String s) {
        boolean OK = true;
        switch (Token.parse(inp)) { /* Enum */
             case FOO:
                    do_foo();
                    break;
             case QUIT:
                    run = false;
                    break;
             case UNKNOWN:
                    print "Unknown" + inp;
                    OK = false;
                    break;
             }
         }
         return OK;
    }
}

扩展器:

class Major extends Base
{

}

我想要的是扩展act,如果super没有处理它,那么尝试在Major中处理它。例如。添加PRINT_STAT("print-statistics", "ps") - 但同时让Base类处理默认值为QUIT

这是一种完全错误的做法吗?

到目前为止我所做的是添加界面通常:

public interface BaseFace
{
      public boolean act_other(String inp);
}

在课堂上Base implements BaseFace

      case UNKNOWN:
          OK = act_other(inp);

在课堂上Major

  public boolean act_other(String inp) { 
       if (inp.equals("blah")) {
            do_blah();
            return true; 
       }
       return false;
  }

这看起来像是可用的设计吗?

主要问题:

是否有一些扩展Token类的好方法,以便我可以在Major中使用与Base中相同的切换方法?我想知道的是,如果有一个是更好的设计,那么如果我必须为Major创建一个新的令牌类,或者如果我以某种方式可以扩展或以其他方式重用现有的。


编辑:概念点是拥有Base类,我可以轻松地在处理各种类型输入的不同项目中重复使用。

4 个答案:

答案 0 :(得分:45)

所有枚举隐含扩展枚举。在Java中,类最多可以扩展一个其他类。

但是,您可以让您的枚举类实现接口

来自this Java tutorial on Enum Types

  

注意:所有枚举都隐式扩展java.lang.Enum。因为类只能扩展一个父类(请参阅声明类),所以Java语言不支持多重继承状态(请参阅状态,实现和类型的多重继承),因此枚举不能扩展其他任何内容。

编辑Java 8:

从Java 8开始,界面可以包含default methods。这允许您在接口中包含方法实现(但不包括状态)。虽然此功能的主要目的是允许公共接口的演变,但您可以使用它来继承定义多个枚举类之间的公共行为的自定义方法。

然而,这可能很脆弱。如果稍后将具有相同签名的方法添加到java.lang.Enum类,则它将覆盖您的默认方法。 (当在类的超类和接口中定义方法时,类实现总是获胜。)

例如:

interface IFoo {
    public default String name() {
        return "foo";
    }
}

enum MyEnum implements IFoo {
    A, B, C
}

System.out.println( MyEnum.A.name() );  // Prints "A", not "foo" - superclass Enum wins

答案 1 :(得分:5)

您的问题似乎是命令模式

的理想选择

将枚举用作受支持操作的逻辑组是一种很好的做法。 IMO,只需一个enum就可以对所有支持的操作进行分组,这将提高代码的可读性。考虑到这一点,令牌枚举应包含所有支持的操作类型

enum Token
{
   FOO("foo", "do_foo"),
   QUIT("quit", "do_quit"),
   PRINT_STATS("print", "do_print_stats"),
   UNKNOWN("unknown", "unknown")
   .....   

}

考虑创建一个接口Actor,它定义一个方法,如下所示:

public interface Actor
{
   public void act();
}

除了拥有单个 Base 类之外,您可以为每个支持的命令设置一个类,例如

public class FooActor implements Actor
{
    public void act()
    {
        do_foo(); //call some method like do_foo
    }
}

public class PrintActor implements Actor
{
    public void act()
    {
        print_stats(); //call some print stats
    }
}

最后,将有一个驱动程序代码将输入要执行的操作,初始化相应的 Actor 并通过调用 act()方法。

public class Driver
{
   public static void main(String[] args)
   {
      String command; // will hold the input string from the user.

      //fetch input from the user and store it in command

      Token token = Token.parse(command);

      switch(token)
      {
         case FOO:
                   new FooActor().act();
                   break;

         case PRINT_STATS:
                   new PrintActor().act();
                   break;
          .... 

      }


   }
}

这样的设计将确保您可以轻松添加新命令,并且代码仍然是模块化的。

答案 2 :(得分:3)

正如其他人所说,你无法扩展枚举。从设计的角度来看,这个解决方案看起来太紧密了。我建议使用更动态的方法。您可以创建某种行为图:

Map<Token, Runnable> behaviors;

可以轻松修改或替换此地图。您甚至可以存储一些预定义行为的集合。例如:

behaviors.get(Token.parse(inp)).run();

(当然需要进行一些额外的检查)

最后一点:在大多数情况下避免继承

答案 3 :(得分:2)

您需要分解界面。毕竟,一个相当普遍的做法是始终从一个接口开始,然后提供一个抽象类来提供一些默认实现。如果你有一个接口,你可以使枚举实现接口。