利用Java枚举实现状态机的想法比较新颖,在某些场景下用处也很大,看了一篇文章不错翻译在此。
-------------------------------------------------------------------------------------------------------------------------------------------
1. 概述
本文讲述利用Java枚举实现简单的状态机。我们也会对比使用这种方法和接口和具体类方式的优势。
2. Java枚举
Java是一个定义了一系列常亮的特殊类。枚举类型更安全,可读性也更高。
下面是一个例子,HR系统同意员工的离职申请的状态转变。
代码语言:javascript复制public enum LeaveRequestState {
Submitted,
Escalated,
Approved
}
我们一般这么用:
代码语言:javascript复制LeaveRequestState state = LeaveRequestState.Submitted;
枚举也可以包括一些方法,可以在枚举中写抽象方法,让每一个实例实现这个方法,这是实现状态机的关键。
Java枚举隐式继承自class java.lang.Enum,因此它们就不能再继承其他类了。不过它们像其他类一样,可以实现其他接口。
代码语言:javascript复制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();
}
注意分号需要放在最后一个枚举常量。如果有一个或多个方法在常量后面,最后一个常量需要带分号。
可以用下面方法使用:
代码语言:javascript复制LeaveRequestState state = LeaveRequestState.Escalated;
assertEquals("Team Leader", state.responsiblePerson());
LeaveRequestState state = LeaveRequestState.Approved;
assertEquals("Department Manager", state.responsiblePerson());
3. 状态机
一个状态机可能是有限状态机或者有限自动化,它是一个用来构造抽象机器的计算模型。
这些机器在特定时间节点只能有一种状态。一种状态到另外一种状态的变化叫做变更(transition)。
状态模式也是知名的GoF的32种设计模式之一。状态机是从数学中借鉴而来的概念。
4. 用枚举实现状态机
通过枚举实现状态机的核心是,我们不需要明确设置状态,而是通过逻辑让状态流转到下一个状态。
代码语言:javascript复制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();
}
用法
代码语言:javascript复制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);
从初始状态通过调用每个枚举常量的nextState()方法实现状态流转,由于Approved已经是最后一个状态了,下一个状态仍然是自己。
5. 枚举实现状态机的优势
通过类或者接口方式实现状态机代码量非常大而且不容易维护。
而Java枚举则是一种简化的形式,是一个常量列表,可以用来定义状态。
而且枚举也可以定义行为,我们可以定义方法来实现状态的转换。
6. 结论
本文主要讲述如何使用Java的枚举来实现状态机并给出了代码和测试案例。
最后讨论了相对于接口或者普通类来说枚举实现状态机的优势。
英语原文:https://www.baeldung.com/java-enum-simple-state-machine
代码:https://github.com/eugenp/tutorials/tree/master/algorithms-miscellaneous-1
如果觉得本文对你有帮助,欢迎点赞评论,欢迎关注我,我将努力创作更多更好的文章。