枚举应通过抽象方法绑定业务逻辑,强制各实例实现专属行为;可封装构造参数传递元数据;状态流转由实例自身决定;禁止存储可变状态,运行时数据须作为参数传入。

直接让每个枚举实例自己“知道怎么干活”,而不是靠外部 if-else 或 switch 去判断后调用不同方法——这是枚举绑定业务逻辑最自然、最安全的方式。
用抽象方法定义统一行为契约
在枚举类中声明一个 abstract 方法(比如 handle()、execute() 或 onEvent()),强制每个枚举常量提供专属实现。编译器会确保不漏写,新增状态时必须补全逻辑,不会静默失效。
- PAYMENT_PENDING 覆盖 handle():检查用户余额并触发支付页跳转
- SHIPPED 覆盖 handle():生成运单号、调用物流接口、更新发货时间
- CANCELLED 覆盖 handle():释放库存、关闭关联优惠券、记录取消原因
结合构造参数封装上下文信息
枚举常量不只是名字,它能自带业务元数据。比如订单状态可携带超时分钟数、是否允许重试、对应的消息模板 ID 等。这些字段在构造时初始化,后续通过 getter 安全复用。
- 声明 private final int timeoutMinutes, String notifyTemplateId
- 构造器接收并赋值:PAYMENT_PENDING(5, "pay_reminder_v2")
- 在 handle() 中直接使用 this.timeoutMinutes 控制定时任务,或 this.notifyTemplateId 渲染通知内容
按事件驱动状态流转,而非硬编码分支
把“收到什么事件、变成什么状态”这个规则下沉到每个枚举实例内部。例如定义 transition(Event event) 方法,由当前状态自行决定下一步走向。
- PAID.transition(Event.SHIP) → 返回 SHIPPED
- PAID.transition(Event.CANCEL) → 返回 CANCELLED
- DELIVERED.transition(...) → 不重写,调用即抛 AbstractMethodError,明确标识终态
避免在枚举里存可变状态或复杂流程
枚举实例是全局唯一的静态对象,不能用来保存订单 ID、用户信息、重试次数等运行时数据。这些必须由调用方作为参数传入方法中。
- ✅ 正确:status.handle(orderId, userId, context)
- ❌ 错误:在枚举里定义 private AtomicInteger retryCount
- 业务动作(如扣减库存、发 MQ)仍应在 service 层执行,枚举只回答“该做什么”和“能变成什么”










