繁体   English   中英

这里的最佳实践是什么,扩展`enum`才是真正有用的(但在Java中是不可能的)?

[英]What would be the best practice here, where extending `enum`s would be really useful (yet impossible in java)?

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

第一个只是一个职位和其他一些领域。 MovingEntityMovingEntity可以移动。 我以前用枚举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的关闭时的默认操作也是如此...)。

最佳做法是什么?

您可能只有一个枚举,带有所有可能的状态。 然后,每个实体声明它们支持的状态:

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 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使用ints,但是主要原因是因为它在枚举甚至还没有存在之前就已经存在。

关于您在评论中的其他问题

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

这是我从您的发言中所了解的。 假设有人提出更改字符状态的请求。 您首先需要检查此字符是否支持状态更改。 因此,您将一直无休止地在阵列上循环。 那是你的问题吗?

如果是这样,则可以使用Set来代替Entity中的数组,该方法带有返回状态是否受支持的方法:

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可以是私有的,但是我的猜测是您应该出于其他目的从其他位置调用此方法。 也许,用户不应具有设置无效状态的选项,因此您的用户界面会在显示选项之前先检查哪些是有效状态。 我希望我很清楚...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM