大部分的状态机都是有限状态机,某些业务环境,或者其他环境中,如果有状态机其实还是很方便的。比如,我是用在了单个客户的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
阅
一键三连呦!,感谢大佬的支持,您的支持就是我的动力!