大部分的状态机都是有限状态机,某些业务环境,或者其他环境中,如果有状态机其实还是很方便的。比如,我是用在了单个客户的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
阅
一键三连呦!,感谢大佬的支持,您的支持就是我的动力!
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全