枚举嵌套枚举

41

我并不是卡住了,而是想找一种简洁的方式来编写我的代码。

基本上,我正在编写一个事件驱动的应用程序。用户触发事件,事件被发送到相应的对象,然后对象处理事件。现在我正在编写事件处理方法,并希望使用 switch 语句来确定如何处理事件。目前,当我在工作整体结构时,事件类非常简单:

public class Event {

    public static enum Action {
        MOVE, FOO, BAR
    }

    private Action action;
    private int duration;

    public Event(Action action, int duration) {
        this.action = action;
        this.duration = duration;
    }

    public Action getAction() {
        return action;
    }

    public int getDuration() {
        return duration;
    }

然后,在另一个类中,我会有如下代码:

public void handleEvent(Event evt) {    
    switch(Event.getAction()) {
        case MOVE: doSomething(); break;
        case FOO:  doSomething(); break;
        case BAR:  doSomething(); break;
        default: break; 
    }
}

我想要做的事情类似于这样(当然,我会将switch语句放入它们自己的函数中,以避免它成为一个难以处理的代码块):

public void handleEvent(Event evt) {    
    switch(Event.getAction()) {
        case MOVE: switch(Event.getAction()) {
                       case UP:    break;
                       case DOWN:  break;
                       case LEFT:  break;
                       case RIGHT: break;
                   }
        case FOO:  break;
        case BAR:  break;
        default:   break; 
    }
}

所以,我想创建嵌套的枚举...像这样:

public static enum Action {
    public enum MOVE {UP, DOWN, LEFT, RIGHT}, FOO, BAR
}

虽然我可以避免这种情况,但使用这种方式会更加方便。因此,虽然上述方法实际上并不可行,但是否有类似的方法可以实现呢?如果我能发送一个带有动作“MOVE.UP”的事件,然后该方法首先将其识别为MOVE类型的动作,然后进一步确定它是在UP方向上特定的动作,那就太好了。这只是一个简单的例子,如果我能制作更长的链,比如"DELETE.PAGE1.PARAGRAPH2.SENTENCE2.WORD11.LETTER3",就更好了。在我看来,我可能只需要使用字符串和大量的if/else语句。希望有更好的方法!(哦,还有,性能在我的情况下很重要,如果这有助于的话)


1
我不会使用枚举来描述你的事件。枚举最适合用于可数、常量状态集。UP、DOWN、LEFT、RIGHT很好,因为它们不太可能改变。MOVE、FOO、BAR感觉应该很容易添加。相反,我会使用多态性(每个事件实现一个doSomething函数,该函数接受游戏状态)。 - ILMTitan
3个回答

47

我相信在Java中,只要非枚举常量排在第一位,你就可以简单地嵌套枚举。

enum Action
{
    FOO,
    BAR;
    enum MOVE
    {
         UP,
         DOWN,
         LEFT,
         RIGHT 
    }
}

这段代码在我的电脑上编译通过,并且提供了你需要的功能。


11
有趣。MOVE不是一个动作。Action.values() 只包含 FOO 和 BAR。 - Ray Tayek
1
虽然 Action.MOVE.UP 是完全有效的。 - Patrick Perini
4
是的,但你需要知道,无法轻松地遍历所有枚举实例。 - Ray Tayek
如果(action == action.MOVE),你会如何实现类似这样的功能 getMoveDirection(); - Shay Ribera
这里的MOVE并不是真正的Action - JSelser
这里的MOVE并不是真正的Action - JSelser

8
也许可以使用继承层次结构来处理这些事件?
那么你可以这样做:
- abstract Event
-- MoveEvent(Direction)
-- FooEvent()
-- BarEvent()

可能更有意义的做法是:

- abstract Event
-- abstract MoveEvent
--- MoveUpEvent
--- MoveDownEvent
--- MoveRightEvent
--- MoveLeftEvent
-- FooEvent
-- BarEvent

如果所有的移动事件都有距离,那么将其传递到MoveEvent构造函数中(这将向下传递)。

5

您可以像这样任意嵌套它们:

package nested;

import java.util.*;
import nested.Citrus.Orange;

interface HasChildren {
    Set<Enum<?>> children();
}

enum Citrus implements HasChildren {
    lemon, lime, orange;
    Set<Enum<?>> children;

    enum Orange implements HasChildren {
        navel, valencia, blood;
        Set<Enum<?>> children;
        enum Navel implements HasChildren {
            washinton, lateLane, caraCaraPink;
            public Set<Enum<?>> children() {
                return null;
            }
        }

        static {
            navel.children = new LinkedHashSet<Enum<?>>();
            navel.children.addAll(EnumSet.allOf(Navel.class));
        }

        enum Blood implements HasChildren {
            moro, taroco;
            public Set<Enum<?>> children() {
                return null;
            }
        }
        static {
            blood.children = new LinkedHashSet<Enum<?>>();
            blood.children.addAll(EnumSet.allOf(Blood.class));
        }
        public Set<Enum<?>> children() {
            return children != null ? Collections.unmodifiableSet(children) : null;
        }
    }
    static {
        orange.children = new LinkedHashSet<Enum<?>>();
        orange.children.addAll(EnumSet.allOf(Orange.class));
    }
    public Set<Enum<?>> children() {
        return children != null ? Collections.unmodifiableSet(children) : null;
    }
}
public class EnumTreeNested {
    static void visit(Class<?> clazz) {
        Object[] enumConstants = clazz.getEnumConstants();
        if (enumConstants[0] instanceof HasChildren)
            for (Object o : enumConstants)
                 visit((HasChildren) o, clazz.getName());
     }

    static void visit(HasChildren hasChildren, String prefix) {
        if (hasChildren instanceof Enum) {
            System.out.println(prefix + ' ' + hasChildren);
            if (hasChildren.children() != null) 
                for (Object o : hasChildren.children())
                    visit((HasChildren) o, prefix + ' ' + hasChildren);
        } else
            System.out.println("other " + hasChildren.getClass());
    }
    static <E extends Enum<E> & HasChildren> Set<E> foo() {
        return null;
    }
    public static void main(String[] args) {
        System.out.println(Citrus.Orange.Navel.washinton);
        visit(Citrus.lemon, "");
        System.out.println("----------------------");
        visit(Citrus.orange, "");
        System.out.println("----------------------");
        visit(Citrus.class);
        System.out.println("----------------------");
    }
}

4
感谢这个答案让我同时学到了枚举和柑橘水果。 - AbetotheMax

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接