应使用枚举配合switch实现状态分流,显式覆盖所有枚举值、禁用default兜底,Java 14+推荐switch表达式,旧版default抛AssertionError;case仅调度不实现业务;状态变量须强类型绑定枚举;优先考虑在枚举内定义抽象方法实现行为穷尽。

直接用枚举配合 switch 实现状态逻辑分流,核心是让每个状态有明确归属、行为可隔离、遗漏能暴露。关键不在语法能不能写,而在结构是否经得起新增状态和多人协作的考验。
必须显式覆盖所有枚举值,禁用 default 兜底
枚举天生封闭,但 switch 不会自动检查你有没有漏写 case。Java 14+ 的 switch 表达式(用 -> 语法)不写 default 就能编译报错,提示新增枚举项时立即暴露问题。旧版本建议 default 中抛 AssertionError,而不是 return null 或空语句——前者运行即崩,倒逼补全;后者静默掩盖缺陷。
- 订单状态有 CREATED、PAID、SHIPPED、DELIVERED、CANCELLED 五个值,switch 就得列五次 case
- 别写 case OrderStatus.PAID:,只需 case PAID:,带类名反而易出错
- 反序列化进来的枚举值要确认是真实实例,不是字符串或 null,否则直接 NPE
每个 case 只调度,不实现具体业务
把发短信、调接口、更新数据库全塞进一个 case 里,会让状态流转主干臃肿且难定位故障点。应该把动作拆成独立函数,case 内只做调用和判断。
- case SHIPPED: → 调用 onEnterShipped() 校验前置条件
- 再调用 updateShipped() 执行发货动作
- 最后用 shouldTransitionToDelivered() 判断是否满足进入下个状态的条件
- 主 switch 只负责赋值:if (shouldTransitionToDelivered()) current = DELIVERED;
状态变量必须强类型绑定,杜绝隐式转换
用 int 或 String 代替枚举来存状态,等于放弃类型安全。current = 999; 编译器不管,运行时才崩。务必用 enum class(C++/C#)、enum(Java)、sealed class(Kotlin)等真正不可扩展的类型。
- Java 中确保枚举是 public 或至少包内可见,否则 switch 报 incompatible types
- C++ 推荐用 scoped enum(enum class),避免裸 enum 导致的整数污染
- 所有状态变更必须通过枚举常量赋值,禁止构造非法值
善用枚举自身方法替代外部 switch
如果每个状态的行为差异固定且不随上下文大幅变化,更彻底的做法是把逻辑定义在枚举内部。每个枚举常量实现同一个抽象方法,天然强制穷尽——加一个新状态,编译就提醒你补方法。
- 定义 public abstract String getDescription(); 在枚举类中
- 每个常量如 CREATED { public String getDescription() { return "待支付"; } }
- 调用时直接 status.getDescription(),完全绕过 switch 分发
- 适合状态行为稳定、复用率高的场景,比如状态文案、图标、默认超时时间等











