Java狀態(tài)機(jī)的一種優(yōu)雅寫(xiě)法分享
狀態(tài)機(jī)是一種數(shù)學(xué)模型,對(duì)于我們業(yè)務(wù)實(shí)現(xiàn)有很大的幫助。
我們可以用非常多的方法實(shí)現(xiàn)狀態(tài)機(jī),比如用茫茫多的if-else來(lái)進(jìn)行條件判斷,但是這種原始的方法并不夠優(yōu)雅,這篇文章就來(lái)介紹一個(gè)狀態(tài)機(jī)優(yōu)雅的實(shí)現(xiàn)方法。
話不多說(shuō),直接進(jìn)入正題。
假設(shè)我們有兩個(gè)狀態(tài)
這個(gè)狀態(tài)轉(zhuǎn)換非常簡(jiǎn)單,我們來(lái)試著用java實(shí)現(xiàn)一下
程序結(jié)構(gòu)如下圖
我們先來(lái)介紹一下?tīng)顟B(tài)的表示
public class StateTransaction { // 當(dāng)前狀態(tài) private StateEnum currentState; // 相對(duì)應(yīng)動(dòng)作 private ActionEnum action; // 下一個(gè)狀態(tài) private StateEnum nextState; // 相應(yīng)事件 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; } // 鏈?zhǔn)匠跏蓟瘜?duì)象 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)的量一共有四個(gè),分別是:
- currentState:表示當(dāng)前狀態(tài)
- action:表示相應(yīng)動(dòng)作
- nextState:表示下一個(gè)狀態(tài)
- event:表示相應(yīng)事件
這個(gè)四元組的含義就是,當(dāng)處于currentState狀態(tài)的時(shí)候,如果發(fā)生了action動(dòng)作,就會(huì)轉(zhuǎn)移到nextState狀態(tài),并且會(huì)觸發(fā)event事件的響應(yīng)。
注意看鏈?zhǔn)匠跏蓟乃膫€(gè)方法,這四個(gè)方法的定義讓狀態(tài)的初始化變得很優(yōu)雅。
接著來(lái)看一下事件,Event是一個(gè)接口,其他具體的事件實(shí)現(xiàn)該接口進(jìn)行某些操作,我們這個(gè)程序就直接打印一些信息,不做復(fù)雜的操作
public interface Event { public String handle(); }
public class PlayBasketballEvent implements Event{ @Override public String handle() { System.out.println("開(kāi)始打籃球"); return "開(kāi)始打籃球"; } }
public class SingDanceRapEvent implements Event{ @Override public String handle() { System.out.println("開(kāi)始唱,跳,rap"); return "開(kāi)始唱,跳,rap"; } }
除此之外,我們還要定義兩個(gè)枚舉類,分別表示狀態(tài)和動(dòng)作
public enum StateEnum { // 打籃球 PLAY_BASKETBALL, // 唱跳rap SING_DANCE_RAP } public enum ActionEnum { // 音樂(lè)起 MUSIC_ON, // 音樂(lè)結(jié)束 MUSIC_OFF }
上面準(zhǔn)備工作都做完后,我們需要一個(gè)狀態(tài)機(jī)類,來(lái)進(jìn)行狀態(tài)轉(zhuǎn)移
public class StateMachine { // 存儲(chǔ)狀態(tài)信息 private List<StateTransaction> stateTransactionList; // 記錄當(dāng)前狀態(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; } // 進(jìn)行狀態(tài)轉(zhuǎn)移 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; } }
上述代碼有兩個(gè)方法比較關(guān)鍵,分別是addone()和execute()
先來(lái)說(shuō)addone(),方法首先初始化一個(gè)StateTransaction對(duì)象,然后放到List里面,最后將這個(gè)對(duì)象返回,我們拿到這個(gè)對(duì)象就可以往里面填內(nèi)容了。
再說(shuō)說(shuō)execute(),這個(gè)方法接收ActionEnum作為參數(shù),然后會(huì)遍歷列表,尋找一條當(dāng)前狀態(tài)經(jīng)過(guò)相應(yīng)動(dòng)作變化得到的下一個(gè)對(duì)象的這么一個(gè)狀態(tài)信息,如果找到了就執(zhí)行event中的handle()方法,并且將當(dāng)前狀態(tài)進(jìn)行轉(zhuǎn)移,最后將StateTransaction返回,如果沒(méi)找到就返回null。
最后來(lái)看一下初始化的方法
public class StateMachineTest { public static void main(String[] args) { StateMachine machine = new StateMachine(StateEnum.PLAY_BASKETBALL); // 打籃球的時(shí)候,一旦音樂(lè)起,就會(huì)開(kāi)始唱跳rap machine.addone().source(StateEnum.PLAY_BASKETBALL).when(ActionEnum.MUSIC_ON) .target(StateEnum.SING_DANCE_RAP).how(new SingDanceRapEvent()); // 唱跳rap的時(shí)候,一旦音樂(lè)停止,就會(huì)開(kāi)始打籃球 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); } }
可以看到,我們直接用鏈?zhǔn)降姆椒ň湍軇?chuàng)建一條狀態(tài)轉(zhuǎn)移信息,非常優(yōu)雅
程序輸出如下
以上就是Java狀態(tài)機(jī)的一種優(yōu)雅寫(xiě)法分享的詳細(xì)內(nèi)容,更多關(guān)于Java狀態(tài)機(jī)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java?Dubbo服務(wù)調(diào)用擴(kuò)展點(diǎn)Filter使用教程
Dubbo是阿里巴巴公司開(kāi)源的一個(gè)高性能優(yōu)秀的服務(wù)框架,使得應(yīng)用可通過(guò)高性能的RPC實(shí)現(xiàn)服務(wù)的輸出和輸入功能,可以和Spring框架無(wú)縫集成2022-12-12Mybatis-config.xml中映射Mapper.xml文件遇到的錯(cuò)誤及解決
這篇文章主要介紹了Mybatis-config.xml中映射Mapper.xml文件遇到的錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06Spring Boot整合Elasticsearch實(shí)現(xiàn)全文搜索引擎案例解析
ElasticSearch作為基于Lucene的搜索服務(wù)器,既可以作為一個(gè)獨(dú)立的服務(wù)部署,也可以簽入Web應(yīng)用中。SpringBoot作為Spring家族的全新框架,使得使用SpringBoot開(kāi)發(fā)Spring應(yīng)用變得非常簡(jiǎn)單,在本案例中我們給大家介紹Spring Boot整合Elasticsearch實(shí)現(xiàn)全文搜索引擎2017-11-11在SpringBoot中配置日志級(jí)別和輸出格式的教程詳解
在開(kāi)發(fā)一個(gè)應(yīng)用程序時(shí),日志記錄是非常重要的一環(huán),SpringBoot提供了多種日志輸出方式和配置選項(xiàng),本文將介紹如何在SpringBoot應(yīng)用程序中配置日志級(jí)別和輸出格式,需要的朋友可以參考下2023-06-06SpringBoot?ScheduledTaskRegistrar解決動(dòng)態(tài)定時(shí)任務(wù)思路詳解
本文將從問(wèn)題出發(fā),詳細(xì)介紹ScheduledTaskRegistrar類是如何解決動(dòng)態(tài)調(diào)整定時(shí)任務(wù)的思路,并給出關(guān)鍵的代碼示例,幫助大家快速地上手學(xué)習(xí)2023-02-02Spring集成Web環(huán)境與SpringMVC組件的擴(kuò)展使用詳解
這篇文章主要介紹了Spring集成Web環(huán)境與SpringMVC組件,它是一個(gè)MVC架構(gòu),用來(lái)簡(jiǎn)化基于MVC架構(gòu)的Web應(yīng)用開(kāi)發(fā)。SpringMVC最重要的就是五大組件2022-08-08J2EE項(xiàng)目代碼編寫(xiě)規(guī)范分享
這篇文章主要介紹了J2EE項(xiàng)目代碼編寫(xiě)規(guī)范分享,需要的朋友可以參考下2014-10-10RabbitMQ實(shí)現(xiàn)Work Queue工作隊(duì)列的示例詳解
工作隊(duì)列(又稱任務(wù)隊(duì)列)的主要思想是避免立即執(zhí)行資源密集型任務(wù),而不得不等待它完成。本篇文章將記錄和分享RabbitMQ工作隊(duì)列相關(guān)的知識(shí)點(diǎn),希望對(duì)大家有所幫助2023-01-01