大部分的狀態機都是有限狀態機,某些業務環境,或者其他環境中,如果有狀態機其實還是很方便的。比如,我是用在了單個客戶的Socket通信上,未連接狀態,我就等連接。已連接狀態,就等待下一步指令狀態。這樣的,邏輯就會簡化許多。
以前在C語言上,自己實現過狀態機,但是,過去好久了。也想通過C#實現,看看是不是方便許多。
狀態機的實現
狀態機接口對象
///?<summary>///?狀態對象///?</summary>public?interface?IStateObject{///?<summary>///?進入狀態///?</summary>void?EnterState();///?<summary>///?離開狀態///?</summary>void?ExitState();///?<summary>///?更新狀態///?</summary>void?UpdateState();}
也可以在 更新狀態里,自己設置下一個狀態。算是轉到指定狀態上。
比如登錄成功
狀態機核心邏輯
///?<summary>///?狀態機///?</summary>public?class?StateMachine{///?<summary>///?運行?Update?時間間隔?毫秒///?</summary>public?int?RunInterval?=?500;///?<summary>///?當前狀態///?</summary>private?string?CurrentState;///?<summary>///?字典存放當前所有對象///?</summary>private?Dictionary<string,?IStateObject>?Dic?=?new();///?<summary>///?當前的線程對象///?</summary>private?Thread?thread;///?<summary>///?是否已經在運行///?</summary>private?bool?IsRun?=?false;public?StateMachine(int?runInterval?=?500){this.RunInterval?=?runInterval;}///?<summary>///?注冊一個狀態對象///?</summary>///?<param?name="stateObject"></param>///?<param?name="istateObject"></param>public?void?Register(string?stateObject,?IStateObject?istateObject){Dic.TryAdd(stateObject,?istateObject);}///?<summary>///?注冊一個狀態對象///?</summary>///?<param?name="stateObject"></param>///?<param?name="istateObject"></param>public?void?Register(Dictionary<string,?IStateObject>?stateObjects){if?(stateObjects?.Any()?==?true){foreach?(var?item?in?stateObjects){Dic.TryAdd(item.Key,?item.Value);}}}///?<summary>///?設置當前狀態///?</summary>///?<param?name="stateObject"></param>public?void?SetState(string?stateObject){if?(CurrentState?!=?stateObject){if?(CurrentState?!=?null?&&?Dic.TryGetValue(CurrentState,?out?var?oldObj)){oldObj.ExitState();}CurrentState?=?stateObject;if?(CurrentState?!=?null?&&?Dic.TryGetValue(CurrentState,?out?var?newObj)){newObj.EnterState();}}}///?<summary>///?自己啟動服務///?</summary>public?void?Start(){if?(!IsRun){IsRun?=?true;thread?=?new?Thread(new?ThreadStart(Run));thread.IsBackground?=?true;thread.Start();Console.WriteLine("狀態機啟動");}}///?<summary>///?自己停止服務///?</summary>public?void?Close(){if?(IsRun){//最后一個狀態直接退出if?(CurrentState?!=?null?&&?Dic.TryGetValue(CurrentState,?out?var?oldObj)){oldObj.ExitState();}IsRun?=?false;try{thread.Interrupt();}catch?(Exception){}Thread.Sleep(50);thread?=?null;Console.WriteLine("狀態機關閉");}}///?<summary>///?線程執行的任務///?</summary>private?void?Run(){try{while?(IsRun){Updata();SpinWait.SpinUntil(()?=>?!IsRun,?RunInterval);}}catch?(Exception)?{?};}///?<summary>///?更新數據///?</summary>public?void?Updata(){if?(CurrentState?!=?null?&&?Dic.TryGetValue(CurrentState,?out?var?objobj)){objobj.UpdateState();}}}
這個是狀態機的核心實現,大佬隨便看一下應該就知道啥意思了。
定義兩個狀態對象
///?<summary>
///?一只貓
///?</summary>
public?class?Cat?:?IStateObject?
{public?void?EnterState(){Console.WriteLine("小貓進來了");}public?void?ExitState(){Console.WriteLine("小貓出去了");}public?void?UpdateState(){Console.WriteLine("小貓在玩逗貓棒!");}
}
///?<summary>
///?一只狗
///?</summary>
public?class?Dog?:?IStateObject?
{public?void?EnterState(){Console.WriteLine("小狗進來了");}public?void?ExitState(){Console.WriteLine("小狗出去了");}public?void?UpdateState(){Console.WriteLine("小狗在玩耍!");}
}
一只貓,一只狗,就可以切換狀態效果了。
測試代碼
static?void?Main(string[]?args)
{StateMachine?stateMachine?=?new?StateMachine(1500);//狀態機//根據當前的不同的狀態,做出不同的事件操作stateMachine.Register(nameof(Cat),?new?Cat());stateMachine.Register(nameof(Dog),?new?Dog());//啟動狀態機stateMachine.Start();//開始執行狀態機//設置當前狀態stateMachine.SetState(nameof(Cat));Thread.Sleep(2000);stateMachine.SetState(nameof(Dog));Thread.Sleep(2000);stateMachine.SetState(nameof(Cat));Thread.Sleep(2000);//狀態機停止stateMachine.Close();Console.WriteLine("狀態機執行完畢!");Console.ReadLine();
}
運行結果

總結
狀態機C#實現完之后,用著還是挺方便的。對于有些流程也可以用狀態機來實現。
代碼地址
https://github.com/kesshei/StateMachineDemo.git
https://gitee.com/kesshei/StateMachineDemo.git
閱
一鍵三連呦!,感謝大佬的支持,您的支持就是我的動力!