3 回答

TA貢獻1801條經驗 獲得超16個贊
一種簡單的變體是以I want to transition from X to Y while applying this function. 枚舉非常適合枚舉狀態機中所有可能/有效的狀態。我們需要一些東西來保持我們的狀態轉換——也許是Map<StateType, StateType>?但我們還需要某種State對象和修改它的方法 - 我們需要一個Map<StateType, Map<StateType, Transition>>. 請參閱下面的一些編譯示例代碼,可以幫助您入門。您可以按照自己喜歡的方式公開State對象(也許使其不可變?)并動態添加過渡。
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;
}
}
}
如果您的State對象類型依賴于當前的StateType.

TA貢獻1887條經驗 獲得超5個贊
如果您使用 Spring,您可以考慮 Spring Statemachine。?
我有一個我廣泛使用的個人設計,我稱之為“泵”。您的狀態機類有一個名為“pump”的函數,它會評估狀態并相應地更新。每個狀態評估可能需要來自外部源(控制器)的一些輸入,例如用戶或 AI。初始化狀態機時需要這些對象,并且通常是抽象實現。然后,您添加應用程序可以覆蓋以捕獲事件的事件回調。這種方法的一個優點是“泵”方法可以從單線程或多線程系統執行。
一旦你的機器建成,你就可以通過簡單地永遠調用泵并提供返回隨機值的控制器來輕松地進行單元測試。這實際上是一個“猴子”測試,以確保您的機器可以處理任何輸入組合而不會崩潰。
然后在你的應用程序中你只需要根據情況提供合適的控制器。
下面是一個非常粗略的狀態機,用于控制一個假設的骰子游戲。我省略了大部分細節,留下了方法的核心。請注意,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) {}
}

TA貢獻1878條經驗 獲得超4個贊
我還建議您在實現自己的狀態機之前檢查兩個框架。狀態機理論對于自己開發來說真的很復雜,特別是沒有太多提及的概念,如子/嵌套狀態機是復雜/成功的狀態機設計所必需的。
一是上面提到的 Spring 狀態機,二是Akka 有限狀態機。
我的個人經驗 Spring State Machine 非常適合對諸如應用程序生命周期之類的事物進行建模,這些狀態包括 STARTING、INITIALISING、RUNNING、MAINTENANCE、ERROR、SHUTDOWN 等……但它對于建模諸如購物圖表之類的事物并不是很好、預訂、信用審批流程等...但它的內存占用太大,無法對數百萬個實例進行建模。
另一方面,Akka FSM 的占用空間確實很小,我個人實現了包含數百萬個狀態機實例的系統,并且它有另一個在 Spring 狀態機中完全缺失的工具。在現代 IT 中,一件事是不可避免的,變化,您建模的任何工作流程/流程都不會隨著時間的推移保持不變,因此您需要機制將這些變化集成到長期運行的工作流程/流程中(我的意思是,會發生什么如果您的流程在最新軟件版本之前啟動并保留舊模型,那么現在您有新版本并且模型已更改,您必須閱讀保留的流程并繼續使用新模型)。Akka 是針對此問題的內置解決方案Event / Schema Evolution。
添加回答
舉報