3 回答

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

TA貢獻(xiàn)1887條經(jīng)驗(yàn) 獲得超5個(gè)贊
如果您使用 Spring,您可以考慮 Spring Statemachine。?
我有一個(gè)我廣泛使用的個(gè)人設(shè)計(jì),我稱之為“泵”。您的狀態(tài)機(jī)類有一個(gè)名為“pump”的函數(shù),它會(huì)評(píng)估狀態(tài)并相應(yīng)地更新。每個(gè)狀態(tài)評(píng)估可能需要來自外部源(控制器)的一些輸入,例如用戶或 AI。初始化狀態(tài)機(jī)時(shí)需要這些對(duì)象,并且通常是抽象實(shí)現(xiàn)。然后,您添加應(yīng)用程序可以覆蓋以捕獲事件的事件回調(diào)。這種方法的一個(gè)優(yōu)點(diǎn)是“泵”方法可以從單線程或多線程系統(tǒng)執(zhí)行。
一旦你的機(jī)器建成,你就可以通過簡單地永遠(yuǎn)調(diào)用泵并提供返回隨機(jī)值的控制器來輕松地進(jìn)行單元測(cè)試。這實(shí)際上是一個(gè)“猴子”測(cè)試,以確保您的機(jī)器可以處理任何輸入組合而不會(huì)崩潰。
然后在你的應(yīng)用程序中你只需要根據(jù)情況提供合適的控制器。
下面是一個(gè)非常粗略的狀態(tài)機(jī),用于控制一個(gè)假設(shè)的骰子游戲。我省略了大部分細(xì)節(jié),留下了方法的核心。請(qǐng)注意,Player.rollDice 的一種實(shí)現(xiàn)可能是一種等待用戶按下按鈕以推進(jìn)游戲的阻塞方法。在這個(gè)方案中,控制游戲的所有邏輯都包含在機(jī)器中,并且可以獨(dú)立于任何 UI 進(jìn)行測(cè)試。
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貢獻(xiàn)1878條經(jīng)驗(yàn) 獲得超4個(gè)贊
我還建議您在實(shí)現(xiàn)自己的狀態(tài)機(jī)之前檢查兩個(gè)框架。狀態(tài)機(jī)理論對(duì)于自己開發(fā)來說真的很復(fù)雜,特別是沒有太多提及的概念,如子/嵌套狀態(tài)機(jī)是復(fù)雜/成功的狀態(tài)機(jī)設(shè)計(jì)所必需的。
一是上面提到的 Spring 狀態(tài)機(jī),二是Akka 有限狀態(tài)機(jī)。
我的個(gè)人經(jīng)驗(yàn) Spring State Machine 非常適合對(duì)諸如應(yīng)用程序生命周期之類的事物進(jìn)行建模,這些狀態(tài)包括 STARTING、INITIALISING、RUNNING、MAINTENANCE、ERROR、SHUTDOWN 等……但它對(duì)于建模諸如購物圖表之類的事物并不是很好、預(yù)訂、信用審批流程等...但它的內(nèi)存占用太大,無法對(duì)數(shù)百萬個(gè)實(shí)例進(jìn)行建模。
另一方面,Akka FSM 的占用空間確實(shí)很小,我個(gè)人實(shí)現(xiàn)了包含數(shù)百萬個(gè)狀態(tài)機(jī)實(shí)例的系統(tǒng),并且它有另一個(gè)在 Spring 狀態(tài)機(jī)中完全缺失的工具。在現(xiàn)代 IT 中,一件事是不可避免的,變化,您建模的任何工作流程/流程都不會(huì)隨著時(shí)間的推移保持不變,因此您需要機(jī)制將這些變化集成到長期運(yùn)行的工作流程/流程中(我的意思是,會(huì)發(fā)生什么如果您的流程在最新軟件版本之前啟動(dòng)并保留舊模型,那么現(xiàn)在您有新版本并且模型已更改,您必須閱讀保留的流程并繼續(xù)使用新模型)。Akka 是針對(duì)此問題的內(nèi)置解決方案Event / Schema Evolution。
添加回答
舉報(bào)