最近在折腾一些控制相关的软件设计,想起来 状态机 这个东西,对解决一些控制系统状态切换还是挺有用的。

状态机(有限状态自动机)网上有很多介绍。简单理解就是定义一系列状态,通过一系列的事件,可以使得状态可以相互之间切换。

如果不使用状态机的思想来编程,那么针对过程的编程方法会使得程序拓展性变差,并且不容易调试。而状态机只需要定义好了各种状态和状态切换之间的事件,你只管触发事件,剩下的事情它自己就自动完成了(毕竟名称叫做有限状态自动机),这对于很多需要定义各种控制阶段的系统简直是完美适配。了解到.NET也有很多库可以实现这些功能,本文主要介绍一下Stateless的应用。

Stateless介绍

Stateless可以创建极简的状态机与对应的工作流。很多项目(包括VisualStudio Extension、AIlab)都有使用到它。

它支持以下特性:

  • 支持各种类型作为状态和触发事件
  • 支持状态继承
  • 支持状态进入/离开事件
  • 支持条件状态转移
  • 支持状态/转移查询

也有几点需要注意的:

  • 它支持异步语法,但是它是单线程的,不是线程安全的。
  • 可以导出DOT graph

安装起来很简单,直接在nuget中安装即可:

Install-Package Stateless

Stateless使用

用起来也挺简单的,以打电话这个事情为例,针对打电话的种种动作和状态做成一个状态机。
需要先定义一些状态和事件/触发器,电话有拨号、接通、留言等事件,有响铃、挂起、挂断等状态:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

//代码来自官方示例,可以在官方github库上找到,略有修改以完整展示功能。

enum Trigger

{

  CallDialed,

  CallConnected,

  LeftMessage,

  PlacedOnHold,

  TakenOffHold,

  PhoneHurledAgainstWall,

  MuteMicrophone,

  UnmuteMicrophone,

  SetVolume

}

enum State

{

  OffHook,

  Ringing,

  Connected,

  OnHold,

  PhoneDestroyed

}

然后就是创建一个状态机了:

1

_machine = new StateMachine<State, Trigger>(() => _state, s => _state = s);

最后也是最需要详细解释的,就是配置状态机的行为了:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

/*

为了解释尽可能多的功能,以下程序修改了官方的代码,可以在官方找可以直接执行的代码。

*/

//使用Permit指示发生某个事件后,从一个状态变换到另外一个状态。

_machine.Configure(State.OffHook)

  .Permit(Trigger.CallDialed, State.Ringing);

//设置一个带参数的事件,这个事件是CallDialed的类型

var _setCalleeTrigger = _machine.SetTriggerParameters<string>(Trigger.CallDialed);

_machine.Configure(State.Ringing)

  //允许重新进入当前的状态,这个过程会触发进入和退出动作

  .PermitReentry(Trigger.Ringing)

  //使用OnEntryFrom指示在触发这个状态的时候,运行某个动作,这里指定的是一个带参数的事件

  .OnEntryFrom(_setCalleeTrigger, callee => OnDialed(callee), "Caller number to call")

  .Permit(Trigger.CallConnected, State.Connected);

_machine.Configure(State.OnHold)

  //定义子状态

  .SubstateOf(State.Connected)

  .Permit(Trigger.TakenOffHold, State.Connected)

  .Permit(Trigger.PhoneHurledAgainstWall, State.PhoneDestroyed);

_machine.Configure(State.Connected)

  //进入状态的时候执行动作

  .OnEntry(t => StartCallTimer())

  //离开状态执行动作

  .OnExit(t => StopCallTimer())

  //状态不变化,但是响应某种事件,和PermitReentry不同,它不会触发进入和退出的动作

  .InternalTransition(Trigger.MuteMicrophone, t => OnMute())

  .InternalTransition(Trigger.UnmuteMicrophone, t => OnUnmute())

  .InternalTransition<int>(_setVolumeTrigger, (volume, t) => OnSetVolume(volume))

  .Permit(Trigger.LeftMessage, State.OffHook)

  .Permit(Trigger.PlacedOnHold, State.OnHold)

  //指定在发生同一种事件的时候,根据事件的参数不同而决定进入不同的状态。

  .PermitIf(_setCalleeTrigger, State.Connected, callee => string.IsNullOrWhiteSpace(callee))

  .PermitIf(_setCalleeTrigger, State.Connected, callee => !string.IsNullOrWhiteSpace(callee))

  //如果没有定义这个事件而发生了这个事件,会弹出异常。通过指定忽略某一类事件,可以避免这个情况。

  .Ignore(Trigger.CallDialled);

//当然也可以使用这个来避免弹出上面说的异常

_machine.OnUnhandledTrigger((state, trigger) => { });

//可以使用异步调用,但是必须要在触发事件的时候,使用FireAsync

_machine.Configure(State.PhoneDestroyed)

  .OnEntryAsync(async () => await SendEmailToAssignee());

配置好了各状态之间的转换,下面就是触发事件了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

public void Dialed(string callee)

{

  //有参数的触发

  _machine.Fire(_setCalleeTrigger, callee);

}

public void Connected()

{

  //无参数的触发

  _machine.Fire(Trigger.CallConnected);

}

public async Task PhoneDestroy()

{

  //异步触发

  await _machine.FireAsync(Trigger.PhoneDestroyed);

}

public string ToDotGraph()

{

  //导出DOT GRAPH

  return UmlDotGraph.Format(_machine.GetInfo());

}

外部调用很简洁:

1

2

3

4

phoneCall.Dialed("Prameela");

phoneCall.Connected();

phoneCall.SetVolume(2);

phoneCall.Hold();

只需要调用事件即可,别的都会按照我们设置好的动作来进行了,非常自动化。

总结

Stateless可以很好地实现状态机,有点事件驱动的编程的感觉,但本质上不同,Stateless核心是各个状态的迁移。

虽然Stateless很小巧方便,但是还有有很多地方不尽如人意(官方说这就是他们自己的设计目标,维持极简):

  • 没有启动和停止的说法,一般在构造函数里面创建就一直有效。
  • 不是线程安全的
  • 拓展性有限

还有一个Appccelerate.StateMachine(地址),这个支持四种不同的状态机实现:

  • Passive State Machine: 同步单线程处理状态转换
  • Active State Machine: 同步多线程处理状态转换
  • Async Passive State Machine: 异步单线程处理状态转换
  • Async Active State Machine: 异步多线程处理状态转换

其中active的是线程安安全的。另外,它还支持状态、事件的持久化,拓展性强。用法差不多,只是配置的关键字上面有一点区别,大家可以自行翻文档。

【转】浅析C# 状态机Stateless相关推荐

  1. .Net轻量状态机Stateless

    很多业务系统开发中,不可避免的会出现状态变化,通常采用的情形可能是使用工作流去完成,但是对于简单场景下,用工作流有点大财小用感觉,比如订单业务中,订单状态的变更,涉及到的状态量不是很多,即使通过简单的 ...

  2. C#状态机Stateless

    最近在折腾一些控制相关的软件设计,想起来状态机这个东西,对解决一些控制系统状态切换还是挺有用的. 状态机(有限状态自动机)网上有很多介绍.简单理解就是定义一系列状态,通过一系列的事件,可以使得状态可以 ...

  3. C# 状态机 Stateless 3.0

    目录标题 Stateless 简介 Stateless 简单用法 Stateless 初级用法 Stateless 进阶用法 .net 库集合 Stateless 简介 Stateless 是基于 C ...

  4. 状态机 Stateless VS StateMachine

    [什么是状态机] 一句话概括: 状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型. 来解释什么是"状态"( State ).现实事物是有不同状态的,例如一个自 ...

  5. 状态机 stateless_Stateless 3.0-.NET Core的状态机库

    状态机 stateless State Machines and business processes that describe a series of states seem like they' ...

  6. Stateless状态机食用示例

    Stateless 是一个 C# 库,它可以帮助我们简化状态机的实现.下面是使用 Stateless 实现一个简单的状态机的示例: Copy using System; using Stateless ...

  7. MapReduce源码分析之作业Job状态机解析(一)简介与正常流程浅析

    作业Job状态机维护了MapReduce作业的整个生命周期,即从提交到运行结束的整个过程.Job状态机被封装在JobImpl中,其主要包括14种状态和19种导致状态发生的事件. 作业Job的全部状态维 ...

  8. MMO坐骑状态机类问题以及解决方案浅析

    1.表现 –坐骑的奔跑动作丢失,表现为骑乘坐骑的时候状态机僵直平移 –在镜像本中马腿抽搐 2.原因 –跑动状态是需要加载到之后才会有跑动状态,状态是由状态参数控制,坐骑的常驻状态参数为1:内存中保留坐 ...

  9. stateless java_JAVA -- stateless4j StateMachine 使用浅析(二)

    回顾: 在上一篇文章 中,我们介绍了stateless4j statemachine的使用入门,这一篇我们介绍 Exit && Entry Action; 废话不多说,show you ...

最新文章

  1. 计算机应用基础全套ppt,计算机应用基础全套PPT电子教案(完整版).ppt
  2. C#-发送接收消息MQ
  3. iOS集成sharesdk遇到的坑
  4. 2021/6/18~19 每天学习python 30分钟 -了解python - python的基本变量概述
  5. 文巾解题 994. 腐烂的橘子
  6. 8除以2表示什么意思_八字中劫财,比肩分别表示什么意思
  7. Python--给数字前固定位数加零
  8. 架构设计:负载均衡层设计方案(3)——Nginx进阶
  9. php trait编译实现,为什么PHP Trait不能实现接口?
  10. 远程teamview下载网址,和ie 下载地址
  11. 嵌入式硬件设计:SoC开发、电源设计、人机交互设计
  12. 物联网 嵌入式 单片机 毕设如何选题 【项目分享】
  13. dubbo源码分析第七篇一服务暴露第三小节一远程暴露内核剖析
  14. 创建一个urdf机器人_ROS机器人Diego 1#制作(十六)创建机器人的urdf模型描述文件详解...
  15. 经典语录(个人喜欢)
  16. (杂)网易云歌单导入到apple music
  17. 《信息处理技术》知识点整理
  18. HTTP 提交方式有哪些
  19. 牛客小白月赛25 D.抽卡
  20. ggplot2入门与进阶(上)

热门文章

  1. 开放域对话系统的属性一致性识别
  2. 网速慢的原因及解决办法!
  3. Dreamwaver cs4破解方法
  4. Data Guard、 GoldenGate 的区别
  5. php window.onload,window.onload,body onload和document.onreadystatechange
  6. iOS超全面试题,面试前看一看,不错
  7. 「JOISC 2014 Day3」稻草人
  8. 人生就是不断突破自我的过程。
  9. java 日历签到功能_自定义Calendar实现签到功能
  10. Unity Addressable内存管理