1. 概述
本文将带你了解状态机的概念,以及如何使用 Java 枚举(Enum)来实现一个状态机。
我们还会对比使用接口和具体类的方式,说明枚举实现的优势。
2. Java 枚举
Java 枚举是一种特殊的类,用于定义一组常量。它提供了类型安全和更清晰的代码结构。
举个例子,假设我们有一个 HR 系统,员工提交请假请求后,需要由团队 Leader 审核,再由部门经理批准。
最简单的枚举如下:
public enum LeaveRequestState {
Submitted,
Escalated,
Approved
}
我们可以直接引用这些状态:
LeaveRequestState state = LeaveRequestState.Submitted;
✅ 枚举中也可以定义方法。 我们可以在枚举中定义一个抽象方法,强制每个枚举实例都实现该方法。这个特性对状态机的实现非常关键。
⚠️ 注意:Java 枚举默认继承自 java.lang.Enum
,因此不能继承其他类,但可以实现接口。
来看一个包含抽象方法的枚举示例:
public enum LeaveRequestState {
Submitted {
@Override
public String responsiblePerson() {
return "Employee";
}
},
Escalated {
@Override
public String responsiblePerson() {
return "Team Leader";
}
},
Approved {
@Override
public String responsiblePerson() {
return "Department Manager";
}
};
public abstract String responsiblePerson();
}
注意最后一个枚举常量后的分号 ;
是必须的,因为后面还有方法定义。
在这个例子中,我们为每个状态指定了负责人:
LeaveRequestState state = LeaveRequestState.Escalated;
assertEquals("Team Leader", state.responsiblePerson());
LeaveRequestState state = LeaveRequestState.Approved;
assertEquals("Department Manager", state.responsiblePerson());
3. 状态机
状态机(也叫有限状态机或有限自动机)是一种用于构建抽象机器的计算模型。它在任意时刻只能处于一个状态,状态之间的转换称为“状态转移”。
虽然数学上可以用状态图和公式来表示,但对我们程序员来说,只要掌握核心思想即可。
状态模式(State Pattern)是 GoF 23 种设计模式之一,它借鉴了数学模型的思想:让对象根据当前状态封装不同的行为。我们可以先定义状态之间的转移逻辑,再分别实现每个状态。
接下来,我们会基于请假流程的例子,实现一个状态机。
4. 使用枚举实现状态机
我们重点来看如何用 Java 枚举实现状态机。虽然也有其他实现方式,但枚举实现是最简洁的一种。
枚举实现的核心思想是:我们不需要手动管理状态的切换,只需要定义好从一个状态到另一个状态的转移逻辑。
来看代码:
public enum LeaveRequestState {
Submitted {
@Override
public LeaveRequestState nextState() {
return Escalated;
}
@Override
public String responsiblePerson() {
return "Employee";
}
},
Escalated {
@Override
public LeaveRequestState nextState() {
return Approved;
}
@Override
public String responsiblePerson() {
return "Team Leader";
}
},
Approved {
@Override
public LeaveRequestState nextState() {
return this;
}
@Override
public String responsiblePerson() {
return "Department Manager";
}
};
public abstract LeaveRequestState nextState();
public abstract String responsiblePerson();
}
这里我们通过 nextState()
方法定义了状态之间的转移逻辑。每个枚举实例都实现了这个方法,表示如何进入下一个状态。
下面是测试代码:
LeaveRequestState state = LeaveRequestState.Submitted;
state = state.nextState();
assertEquals(LeaveRequestState.Escalated, state);
state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);
state = state.nextState();
assertEquals(LeaveRequestState.Approved, state);
✅ 我们从 Submitted
状态开始,依次调用 nextState()
方法完成状态转移。
⚠️ 注意:Approved
是终止状态,调用 nextState()
后不会再变化。
5. 使用枚举实现状态机的优势
相比使用接口 + 实现类的方式,枚举实现有以下优势:
- ✅ 代码更简洁:所有状态和转移逻辑都集中在枚举中
- ✅ 类型安全:避免非法状态的存在
- ✅ 易于维护:逻辑集中,改动影响范围小
- ✅ 可读性强:枚举本身就是对状态的清晰表达
6. 总结
本文介绍了状态机的基本概念,并演示了如何用 Java 枚举实现一个简单的请假审批状态机。
相比传统的接口实现方式,枚举实现更加干净、直观,适合处理状态不多、逻辑简单的业务场景。
所有代码示例都可以在我们的 GitHub 仓库 中找到。