Java普通类使用抽象类子类实现随机状态切换问题咨询
问题1:是否需要为Car类创建接收State类型参数的构造方法
不是强制要求,但非常推荐加,理由如下:
- 如果只保留无参构造,实例化Car后必须手动调用setter方法给
state属性赋值,很容易出现漏赋值导致state为null,后续调用状态方法时空指针。 - 带State参数的构造方法可以强制要求Car实例在创建时就传入合法初始状态,保证对象初始化完成后就是可用状态,避免非法状态问题。
- 可以同时保留无参构造,在无参构造里设置一个默认初始状态(比如默认Rest状态),兼顾使用灵活性和安全性。
参考实现:
import java.util.Objects; public class Car { private State state; // 带初始状态的构造方法 public Car(State initState) { // 加非空校验,禁止传null状态 this.state = Objects.requireNonNull(initState, "初始状态不能为null"); } // 无参构造,给默认初始状态 public Car() { this(new Rest()); } }
问题2:是否需要在State类中创建枚举实现随机状态选择?Car类如何处理随机状态切换逻辑
完全没必要把枚举定义在State抽象类内部,更不建议把随机选状态的逻辑耦合在State抽象类里,你现在写的chooseRandomState方法固定返回new GotoXY()根本没有随机效果,而且如果把所有子类的实例化逻辑写在抽象父类里,后续新增State子类必须修改抽象类代码,违反开闭原则。
更合理的实现方式如下:
- 枚举的作用是统一维护所有状态类型,避免随机选择时漏写、错写状态,单独定义状态枚举即可,不需要嵌套在State类中。
- 状态是Car持有的属性,状态切换的控制权应该归Car所有,不要把切换逻辑放到State类中,State抽象类只需要定义所有状态子类共有的行为抽象即可。
具体实现步骤
- 单独定义状态枚举,和四个State子类一一对应
public enum CarStateEnum { GOTO_XY, REST, SHAKE, CHASE }
- 精简State抽象类,只保留公共行为定义,移除所有和随机选状态相关的耦合代码
public abstract class State { // 获取当前状态名称 public abstract String getCurrentStateName(); // 定义当前状态下要执行的逻辑,传入Car实例方便后续触发状态切换 public abstract void execute(Car car); }
- 实现各个State子类,以Rest类为例:
public class Rest extends State { @Override public String getCurrentStateName() { return "休息中"; } @Override public void execute(Car car) { System.out.println("车辆停靠休息"); // 当前状态逻辑执行完成后,通知Car切换状态 car.switchRandomState(); } } // GotoXY、Shake、Chase三个子类按相同逻辑实现即可
- 在Car类中实现随机状态切换逻辑,统一维护状态映射关系:
import java.util.EnumMap; import java.util.Random; import java.util.function.Supplier; public class Car { private State state; // 维护枚举和状态实例生成器的映射,新增状态只需要在这里加注册代码即可 private static final EnumMap<CarStateEnum, Supplier<State>> STATE_FACTORY = new EnumMap<>(CarStateEnum.class); private static final Random RANDOM = new Random(); // 静态块注册所有状态 static { STATE_FACTORY.put(CarStateEnum.GOTO_XY, GotoXY::new); STATE_FACTORY.put(CarStateEnum.REST, Rest::new); STATE_FACTORY.put(CarStateEnum.SHAKE, Shake::new); STATE_FACTORY.put(CarStateEnum.CHASE, Chase::new); } public Car(State initState) { this.state = initState; } public Car() { this(new Rest()); } // 随机切换状态方法 public void switchRandomState() { CarStateEnum[] allStates = CarStateEnum.values(); // 随机选中一个状态枚举 CarStateEnum randomState = allStates[RANDOM.nextInt(allStates.length)]; // 生成对应状态实例赋值 this.state = STATE_FACTORY.get(randomState).get(); System.out.println("状态切换完成,当前状态:" + state.getCurrentStateName()); } // 对外暴露的运行入口 public void run() { state.execute(this); } }
额外优化建议
- 如果你的State子类没有自定义的成员变量,只是封装状态行为,完全可以把各个State类写成单例,不用每次切换都new新对象,减少不必要的对象创建。
- 如果你觉得写枚举麻烦,也可以直接维护一个存储State生成器的列表,直接从列表随机选元素,只是用枚举的方式类型更安全,后续维护更方便。
内容的提问来源于stack exchange,提问作者AliCa
相关产品推荐
相关产品推荐

