Java狀態(tài)機的一種優(yōu)雅寫法分享
狀態(tài)機是一種數學模型,對于我們業(yè)務實現有很大的幫助。
我們可以用非常多的方法實現狀態(tài)機,比如用茫茫多的if-else來進行條件判斷,但是這種原始的方法并不夠優(yōu)雅,這篇文章就來介紹一個狀態(tài)機優(yōu)雅的實現方法。
話不多說,直接進入正題。
假設我們有兩個狀態(tài)
這個狀態(tài)轉換非常簡單,我們來試著用java實現一下
程序結構如下圖
我們先來介紹一下狀態(tài)的表示
public class StateTransaction { // 當前狀態(tài) private StateEnum currentState; // 相對應動作 private ActionEnum action; // 下一個狀態(tài) private StateEnum nextState; // 相應事件 private Event event; public StateTransaction() { } public StateEnum getCurrentState() { return currentState; } public ActionEnum getAction() { return action; } public StateEnum getNextState() { return nextState; } public Event getEvent() { return event; } // 鏈式初始化對象 public StateTransaction source(StateEnum state) { currentState = state; return this; } public StateTransaction when(ActionEnum action) { this.action = action; return this; } public StateTransaction target(StateEnum state) { nextState = state; return this; } public StateTransaction how(Event event) { this.event = event; return this; } }
可以看到,表示狀態(tài)的量一共有四個,分別是:
- currentState:表示當前狀態(tài)
- action:表示相應動作
- nextState:表示下一個狀態(tài)
- event:表示相應事件
這個四元組的含義就是,當處于currentState狀態(tài)的時候,如果發(fā)生了action動作,就會轉移到nextState狀態(tài),并且會觸發(fā)event事件的響應。
注意看鏈式初始化的四個方法,這四個方法的定義讓狀態(tài)的初始化變得很優(yōu)雅。
接著來看一下事件,Event是一個接口,其他具體的事件實現該接口進行某些操作,我們這個程序就直接打印一些信息,不做復雜的操作
public interface Event { public String handle(); }
public class PlayBasketballEvent implements Event{ @Override public String handle() { System.out.println("開始打籃球"); return "開始打籃球"; } }
public class SingDanceRapEvent implements Event{ @Override public String handle() { System.out.println("開始唱,跳,rap"); return "開始唱,跳,rap"; } }
除此之外,我們還要定義兩個枚舉類,分別表示狀態(tài)和動作
public enum StateEnum { // 打籃球 PLAY_BASKETBALL, // 唱跳rap SING_DANCE_RAP } public enum ActionEnum { // 音樂起 MUSIC_ON, // 音樂結束 MUSIC_OFF }
上面準備工作都做完后,我們需要一個狀態(tài)機類,來進行狀態(tài)轉移
public class StateMachine { // 存儲狀態(tài)信息 private List<StateTransaction> stateTransactionList; // 記錄當前狀態(tài) private StateEnum currentState; public StateMachine(StateEnum state) { currentState = state; stateTransactionList = new ArrayList<>(); } // 添加一條狀態(tài)信息 public StateTransaction addone() { StateTransaction stateTransaction = new StateTransaction(); stateTransactionList.add(stateTransaction); return stateTransaction; } // 進行狀態(tài)轉移 public StateTransaction execute(ActionEnum action) { for(int i=0; i<stateTransactionList.size(); i++) { if(currentState==stateTransactionList.get(i).getCurrentState() && action==stateTransactionList.get(i).getAction()) { stateTransactionList.get(i).getEvent().handle(); currentState = stateTransactionList.get(i).getNextState(); return stateTransactionList.get(i); } } return null; } }
上述代碼有兩個方法比較關鍵,分別是addone()和execute()
先來說addone(),方法首先初始化一個StateTransaction對象,然后放到List里面,最后將這個對象返回,我們拿到這個對象就可以往里面填內容了。
再說說execute(),這個方法接收ActionEnum作為參數,然后會遍歷列表,尋找一條當前狀態(tài)經過相應動作變化得到的下一個對象的這么一個狀態(tài)信息,如果找到了就執(zhí)行event中的handle()方法,并且將當前狀態(tài)進行轉移,最后將StateTransaction返回,如果沒找到就返回null。
最后來看一下初始化的方法
public class StateMachineTest { public static void main(String[] args) { StateMachine machine = new StateMachine(StateEnum.PLAY_BASKETBALL); // 打籃球的時候,一旦音樂起,就會開始唱跳rap machine.addone().source(StateEnum.PLAY_BASKETBALL).when(ActionEnum.MUSIC_ON) .target(StateEnum.SING_DANCE_RAP).how(new SingDanceRapEvent()); // 唱跳rap的時候,一旦音樂停止,就會開始打籃球 machine.addone().source(StateEnum.SING_DANCE_RAP).when(ActionEnum.MUSIC_OFF) .target(StateEnum.PLAY_BASKETBALL).how(new PlayBasketballEvent()); machine.execute(ActionEnum.MUSIC_ON); machine.execute(ActionEnum.MUSIC_OFF); } }
可以看到,我們直接用鏈式的方法就能創(chuàng)建一條狀態(tài)轉移信息,非常優(yōu)雅
程序輸出如下
以上就是Java狀態(tài)機的一種優(yōu)雅寫法分享的詳細內容,更多關于Java狀態(tài)機的資料請關注腳本之家其它相關文章!
相關文章
Mybatis-config.xml中映射Mapper.xml文件遇到的錯誤及解決
這篇文章主要介紹了Mybatis-config.xml中映射Mapper.xml文件遇到的錯誤及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-06-06Spring Boot整合Elasticsearch實現全文搜索引擎案例解析
ElasticSearch作為基于Lucene的搜索服務器,既可以作為一個獨立的服務部署,也可以簽入Web應用中。SpringBoot作為Spring家族的全新框架,使得使用SpringBoot開發(fā)Spring應用變得非常簡單,在本案例中我們給大家介紹Spring Boot整合Elasticsearch實現全文搜索引擎2017-11-11SpringBoot?ScheduledTaskRegistrar解決動態(tài)定時任務思路詳解
本文將從問題出發(fā),詳細介紹ScheduledTaskRegistrar類是如何解決動態(tài)調整定時任務的思路,并給出關鍵的代碼示例,幫助大家快速地上手學習2023-02-02Spring集成Web環(huán)境與SpringMVC組件的擴展使用詳解
這篇文章主要介紹了Spring集成Web環(huán)境與SpringMVC組件,它是一個MVC架構,用來簡化基于MVC架構的Web應用開發(fā)。SpringMVC最重要的就是五大組件2022-08-08