40

有这样的东西:

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为 ifsuper不处理它然后尝试在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?我想知道是否有一个更好的设计,第二个是我是否必须创建一个新的 Token 类,Major或者我是否可以以某种方式扩展或以其他方式重用现有的。


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

4

4 回答 4

55

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

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

这个关于枚举类型的 Java 教程

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

为 Java 8 编辑:

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

但是,这可能很脆弱。如果稍后将具有相同签名的方法添加到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
于 2013-03-16T15:16:17.033 回答
7

Your problem seems a good candidate for the Command Pattern

It is a good practice to use an enum as a logical group of supported actions. IMO, having a single enum to group all supported actions will improve the readability of your code. With this in mind, the Token enum should contain all the supported action types

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

}

Consider creating an interface Actor which defines an a method say act as shown below:

public interface Actor
{
   public void act();
}

Instead of having a single Base class that does too may things, you can have one class per supported command for e.g.

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
    }
}

Finally, there will be a driver code that will take in as input the action to be performed, initialize the appropriate Actor and execute the action by invoking the act() method.

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;
          .... 

      }


   }
}

Such a design will ensure that you can easily add new commands and the code remains modular.

于 2013-03-16T16:01:19.400 回答
3

As other say here, You can't extend enum. From design perspective this solution looks like it's too tightly coupled. I would advise to use more dynamic approach for this. You can create some kind of behavior map:

Map<Token, Runnable> behaviors;

This map could be easily modified or replaced. You can even store some sets of those predefined behaviors. In example:

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

(some additional checks are needed here of course)

And last note: in most cases avoid inheritance

于 2013-03-16T15:28:10.767 回答
2

您需要考虑一个接口。毕竟,总是从一个接口开始,然后提供一个抽象类来提供一些默认实现,这是一种相当普遍的做法。如果你有一个接口,你可以让枚举实现这个接口。

于 2013-03-16T15:17:22.897 回答