Java 简单状态转换的状态机方法
我正在研究创建一个非常简单的状态机。我的状态机将包含以下3种状态:Java 简单状态转换的状态机方法,java,state,state-machine,state-pattern,Java,State,State Machine,State Pattern,我正在研究创建一个非常简单的状态机。我的状态机将包含以下3种状态: public enum States { PENDING, ACTIVE, DONE } 这里可能存在多个转换+启动状态,具体来说: 初始状态:挂起或活动 过渡: PENDING->ACTIVE PENDING->DONE ACTIVE->DONE 我正在研究表示这些状态的方法和控制转换的可能状态机。我已经研究了一种基于枚举的方法,例如,但我还想向客户端公开状态转换,我不确定这种方法是否合理 我还研究了
public enum States {
PENDING,
ACTIVE,
DONE
}
这里可能存在多个转换+启动状态,具体来说:
初始状态:挂起或活动
过渡:
PENDING->ACTIVE
PENDING->DONE
ACTIVE->DONE
有人对满足这个标准的简单状态机实现有什么建议吗?我甚至在想一些基本的事情,比如使用转换表来存储转换,并在其中封装状态概念,使用转换表来确定下一个可能的状态。其中一个简单的变体是以
的形式保存转换,我想在应用此转换时从X转换到Y功能
。枚举非常适合枚举状态机中所有可能/有效的状态。我们需要一些东西来保持我们的状态转换-也许是一个映射
?但是我们还需要某种类型的状态
对象和修改它的方法-我们需要一个映射
。请参阅下面的一些编译示例代码,这些代码将帮助您开始。您可以随意公开状态
对象(可能使其不可变?),并动态添加转换
import java.util.EnumMap;
import java.util.Map;
import java.util.function.Function;
class StackOverflowQuestion57661787 {
enum StateType {
PENDING,
ACTIVE,
DONE
}
//Made the name explicit here to ease readability
public interface Transition extends Function<State, State> { }
public static class State {
public StateType type;
//TODO: some real data to manipulate, or make it immutable
public Object data;
}
public static class StateMachine {
private final Map<StateType, Map<StateType, Transition>> transitions =
new EnumMap<>(StateType.class);
private State state;
public StateMachine(State initialState) {
this.state = initialState;
for (StateType value : StateType.values()) {
transitions.put(value, new EnumMap<>(StateType.class));
}
}
public void addTransition(
StateType input,
StateType output,
Transition transition
) {
//TODO: handle collisions? multiple transitions for a given
// output statetype seems like a strange use-case
transitions.get(input).put(output, transition);
}
public void moveTo(StateType toType) {
Transition transition = transitions.get(state.type).get(toType);
if (transition == null) {
//TODO: handle me
throw new RuntimeException();
}
//transition should modify the states "type" too OR
//you implement it here
state = transition.apply(state);
}
public State getState() {
return state;
}
}
}
import java.util.EnumMap;
导入java.util.Map;
导入java.util.function.function;
类堆栈溢出问题57661787{
枚举状态类型{
悬而未决的
活跃的,
完成
}
//在此处明确了名称,以便于阅读
公共接口转换扩展函数{}
公共静态类状态{
公共状态类型;
//TODO:一些实际数据需要操作,或使其不可变
公共对象数据;
}
公共静态类状态机{
私有最终映射转换=
新的EnumMap(StateType.class);
私营国家;
公共状态机(状态初始状态){
this.state=初始状态;
for(StateType值:StateType.values()){
transitions.put(值,新枚举映射(StateType.class));
}
}
公共空间转换(
状态类型输入,
状态类型输出,
过渡
) {
//TODO:处理冲突?给定时间的多个转换
//输出状态类型似乎是一个奇怪的用例
转换.get(输入).put(输出,转换);
}
public void moveTo(StateType toType){
Transition Transition=transitions.get(state.type).get(toType);
if(transition==null){
//托多:对付我
抛出新的RuntimeException();
}
//转换也应修改状态“类型”,或
//你在这里实现它
状态=转换。应用(状态);
}
公共状态getState(){
返回状态;
}
}
}
你必须达到一个更复杂的抽象的解决方案,如果你的代码>状态< /代码>对象类型依赖于当前<代码> Stestype < /C> > < P>如果你使用Spring,你可以考虑Spring StaseMaCHIN。
我有一个我广泛使用的个人设计,我称之为“泵”。您的状态机类有一个名为“pump”的函数,该函数计算状态并相应更新。每个状态评估可能需要来自外部源(控制器)的一些输入,如用户或AI。这些对象在初始化状态机时是必需的,通常是抽象实现。然后添加应用程序可以覆盖以捕获事件的事件回调。这种方法的一个优点是“泵”方法可以从单线程或多线程系统执行 一旦您的机器建成,您就可以轻松地进行单元测试,只需调用pump forever并提供返回随机值的控制器。这将是一个有效的“猴子”测试,以确保您的机器可以处理任何输入组合而不会崩溃 然后在应用程序中,您只需要根据情况提供适当的控制器 下面是一个非常粗糙的状态机来控制一个假想的骰子游戏。我省略了大部分细节,留下了方法的要点。请注意,Player.rollDice的一个实现可能是一个阻塞方法,它等待用户点击按钮来推进游戏。在这个方案中,控制游戏的所有逻辑都包含在机器中,可以独立于任何UI进行测试
interface Player {
boolean rollDice();
}
class Game {
int state;
Player [] players;
int currentPlayer;
int dice;
void pump() {
switch (state) {
case ROLL_DICE:
if (players[currentPlayer].rollDice()) {
dice = Math.rand() % 6 + 1;
onDiceRolled(dice);
state = TAKE_TURN;
}
break;
case TAKE_TURN:
...
break;
}
}
// base method does nothing. Users can override to handle major state transitions.
protected void onDiceRolled(int dice) {}
}
谢谢-这是非常有用的。你可以使用spring状态机非常整洁和易于使用