You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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抽象类只需要定义所有状态子类共有的行为抽象即可。

具体实现步骤

  1. 单独定义状态枚举,和四个State子类一一对应
public enum CarStateEnum {
    GOTO_XY, REST, SHAKE, CHASE
}
  1. 精简State抽象类,只保留公共行为定义,移除所有和随机选状态相关的耦合代码
public abstract class State {
    // 获取当前状态名称
    public abstract String getCurrentStateName();
    // 定义当前状态下要执行的逻辑,传入Car实例方便后续触发状态切换
    public abstract void execute(Car car);
}
  1. 实现各个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三个子类按相同逻辑实现即可
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.05 16:15:46