我正在制作游戏,并且我有一组课程: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关闭时的默认操作也是......)。
这里最好的做法是什么?
答案 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可能是私有的,但我猜你应该从其他地方调用此方法用于其他目的。也许,用户不应该选择设置无效状态,因此您的用户界面将首先检查显示选项之前的有效状态。 我希望我能清楚......