[英]What would be the best practice here, where extending `enum`s would be really useful (yet impossible in java)?
我正在制作游戏,并且有一组类: Character
扩展MovingEntity
扩展Entity
。
第一个只是一个职位和其他一些领域。 MovingEntity
, 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的关闭时的默认操作也是如此...)。
最佳做法是什么?
您可能只有一个枚举,带有所有可能的状态。 然后,每个实体声明它们支持的状态:
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.