这里最好的做法是什么,扩展`enum`s会非常有用(在java中是不可能的)?

时间:2016-06-13 03:16:47

标签: java enums

我正在制作游戏,并且我有一组课程:Character扩展MovingEntity扩展Entity

第一个只有一个位置和一些其他领域。顾名思义,MovingEntity可以移动。我曾经用枚举enum State{IDLE, MOVING}来表示这个。但是,当我实现Character时,我遇到了一个问题,因为它们也可以攻击!

所以,有一刻我正在处理一个尴尬的问题

Class MovingEntity extends Entity{
  public enum State{
    IDLE, MOVING;
  }
}
Class Character extends MovingEntity {
  public enum CharacterState{
    IDLE, MOVING, ATTACKING
}

当我添加更复杂的角色时,甚至更多“枚举覆盖”。所以我最终切换到public static final int常量...但我在这里读到这被认为是一种非常糟糕的做法(我不明白为什么,因为Java的API这样做(KeyEvent.VK_stuff是ints,JFrame关闭时的默认操作也是......)。

这里最好的做法是什么?

1 个答案:

答案 0 :(得分:2)

你可以有一个枚举,包含所有可能的状态。然后,每个实体声明它们支持哪些状态:

enum State{
    IDLE, MOVING, ATTACKING;
}

class Entity {
    private State[] states;

    protected Entity(State... states) {
        this.states = states;
    }

}

class Character extends Entity{
    public Character() {
        super(State.IDLE, State.MOVING, State.ATTACKING);
    }
}

class MovingEntity extends Entity{
    public MovingEntity() {
        super(State.IDLE, State.MOVING);
    }
}

如果您创建专门的角色,您甚至可以继承"继承"来自父母的陈述。

class FastMovingEntity extends MovingEntity{
    public FastMovingEntity() {
        super(State.MOVING_FAST);
    }
}

class MovingEntity extends Entity{
    public MovingEntity(State... states) {
        super(...);
    }
}

为何选择枚举?

我自己认为枚举比常量更受欢迎,因为它们是强类型的,更容易阅读。 例如:

doStuff(int state);
doStuff(State state);

第二种方法不言而喻,就争论而言,名称可能更好:)。此外,边界更容易验证,无论是有效状态还是空状态。 (而不是有一系列有效的整数,必须通过javadoc记录,以便用户知道如何使用你的方法)

最后,enum允许你添加行为(方法),这个常量不允许你这样做。

例如:

enum State {
    IDLE, MOVING, ATTACKING(false), MOVING_FAST;

    private boolean someFlag;

    State(boolean someFlag) {
        this.someFlag = someFlag;
    }

    State() {
        this(true);
    }

    public boolean isSomeFlag() {
        return someFlag;
    }
}

此外,KeyEvent.VK_stuff使用整数,但主要原因仅仅是因为它在枚举之前就存在了。

关于评论中的其他问题

  

每次我在每个类中使用一个State变量,实际上   验证它是一个有效状态,我必须检查它是否相等   在State [] states数组中的某个值?

以下是我从您的陈述中理解的内容。让我们说一个请求是为了改变一个角色的状态。您首先需要检查此字符是否支持状态更改。所以你最终会一直在数组上循环。那是你的问题吗?

如果是这样,那么您可以使用Set来代替实体中的数组,并使用返回状态是否受支持的方法:

class Entity {
    private EnumSet<State> supportedStates;
    private State currentState;

    protected Entity(State... state) {
        states = EnumSet.copyOf(Arrays.asList(state));
    }

    //Assumes you are using these values elsewhere, otherwise - private
    public boolean isStateSupported(State state){
        return supportedStates.contains(state);
    }

    public void setCurrentState(State currentState){
        if(!isStateSupported(currentState){
             throw new IllegalStateException();
        }
        this.currentState = currentState;
    }
    public State getCurrentState(){
        return currentState;
    }
}

编辑(6月15日):我已经添加了方法setCurrentState。使用此方法,您可以设置当前状态,该状态首先验证该值是否受支持(isStateSupported)。如果支持状态列表仅在内部用于验证,则isStateSupported可能是私有的,但我猜你应该从其他地方调用此方法用于其他目的。也许,用户不应该选择设置无效状态,因此您的用户界面将首先检查显示选项之前的有效状态。 我希望我能清楚......