2016-09-29 72 views
2

我一直在reading up on State Machines,因爲它可能需要用於我的下一個項目。我在網上找到的大多數例子都展示瞭如何從StateA轉到StateB。但是如果你的下一個想要的狀態不是鄰接狀態呢?是否有任何共同的模式/做法來實現這一目標?理想情況下在Java中,但我也可以閱讀其他編程語言。如果您的目標狀態不是下一個狀態,那麼應使用哪種狀態機設計?

# Example States 
WakeUp->Get Dressed->Get Car Keys->Get in Car->Drive to Work->Work 

Current State: Get in Car 

問題解決

# Scenario 1: Desired State == Work 
Forgot car keys, so you have to return to previous state and then move forward in states again. 

# Scenario 2: Desired State == Work 
Have car keys, so move forward in states to get to Desired State. 

這很可能是國機可能無法完美地解決這個問題,我只是需要手工工藝的邏輯,我不介意,但認爲我會d遵循一種通用的設計模式來幫助他人理解它。

從上面的例子中,我不必擔心'內部'狀態,這對我正在處理的項目也是如此;以防萬一在可能的解決方案中發揮作用。

回答

4

這是一種定義狀態機的簡單方法。

在枚舉中定義所有你想要的狀態。

enum StateType { 
    WAKE_UP, GET_DRESSED, GET_CAR_KEYS, GET_IN_CAR, DRIVE_TO_WORK, WORK 
} 

有無,其控制狀態的的statemachine,並且執行對的statemachine的動作的狀態的界面。狀態然後返回到下一個狀態。

interface State { 
    StateType next(StateMachine sm); 
} 

多種類型

class GetInCarState implements State { 
    @Override 
    public StateType next(StateMachine sm) { 
     if (sm.hasKeys()) { 
      return StateType.DRIVE_TO_WORK; 
     } 
     return StateType.GET_CAR_KEYS; 
    } 
} 

實現這種狀態現在定義狀態機

class StateMachine { 
    private Map<StateType, State> states = new HashMap<StateType, State>() {{ 
     put(StateType.WAKE_UP, new WakeUpState()); 
     put(StateType.GET_DRESSED, new GetDressedState()); 
     put(StateType.GET_CAR_KEYS, new GetCarKeysState()); 
     put(StateType.GET_IN_CAR, new GetInCarState()); 
     put(StateType.DRIVE_TO_WORK, new DriveToWorkState()); 
     put(StateType.WORK, new WorkState()); 
    }}; 

    private StateType currentState = StateType.WAKE_UP; 

    private boolean hasCarKeys; 

    public boolean hasKeys() { 
     return hasCarKeys; 
    } 

    public void setHasKeys(boolean hasKeys) { 
     hasCarKeys = hasKeys; 
    } 

    public void update() { 
     currentState = states.get(currentState).next(this); 
    } 
} 
+0

尼斯之一。幾個建議:(1)StateType.DriveToWork - 你可能意味着DRIVE_TO_WORK; (2)通過在enum類型中移動next方法將'GetInCarState'和'StateType.DRIVE_TO_WORK'結合起來就可以實現你的例子 - 它將消除任何需要通過StateType進行映射的情況。 – bashnesnos

+0

謝謝(1):)對於第二;我也在考慮讓枚舉定義'next'方法,但決定不採用這種方法。通過不將實現耦合到枚舉中,每個狀態可以有多個表示。這可能有助於爲測試創建模擬狀態,並可以在以後創建類似的狀態機而無需創建全新的枚舉。 – flakes

+1

是的,這是所有OOP時間的大問題 - 抽象或不抽象:-)看起來你更喜歡首先抽象:-) – bashnesnos