当前位置: 首页 > news >正文

C# 状态机

引言

在业务处理中, 经常需要处理业务对象的状态转换, 比如 bug 状态管理、订单状态管理等, 这类问题可依照状态的复杂度,可以有不同的解决方案。

  1. 简单的顺序状态管理
    如果状态数量很少,同时状态是按照一个方向流转,就可以归到这类。 对应的解决方案很简单, 在业务对象中增加一个表示状态的枚举字段即可。

  2. 复杂的 BPM 状态管理
    这里复杂的状态管理, 典型特征是包含 BPM 的 split/join, 比如合同的会签, 对应的解决方案就使用重量级的工作流引擎, 比如 Java 的 flowable、camunda、 activiti, C#的 Elsa Workflows 等。

  3. 中等复杂的状态管理
    我将不含 BPM 的 split/join 情形的都归到中等复杂程度,最佳解决方案是使用状态机,在每个业务对象中内嵌一个状态机,由状态机复杂状态转换。

对于简单的状态管理,往往后期会逐渐会变得不那么简单,所以, 对于简单的状态管理,我也推荐使用状态机,甚至这么说,只要不涉及到 BPM split/join, 使用状态机都是最佳方案。

状态机的几个概念

  1. 状态转换 transition
    目标状态仅由前置状态经过一个事件触发实现状态转换。

  2. 守卫条件 Guard condition
    从前置状态可以无条件地通过一个触发条件转换到目标状态,也可以有条件地通过触发事件转换。
    这里的条件在状态机中被叫做 guard condition。
    需要说明的是, guard condition 不应该被理解成状态转换的 pre check 条件,而是不同的目标状态的的区分条件。

 (A) ----triggerB (condition1) --> (B1)|| -----triggerB (condition2) --> (B2)

C# Stateless 状态机开源库

Stateless github 是 C#中最流行的状态机实现,功能非常强大:

  • 支持守卫 condition
  • 支持带参数的 trigger
  • 内建很多事件可供绑定
  • 可进行触发检查
  • 支持父子状态

示例代码

···csharp
using System.Runtime.CompilerServices;
using Stateless;

namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
// Console.WriteLine("==================");
// Order goodsOrder = new Order(OrderState.Created);
// goodsOrder.isVirtualOrder = false;
// goodsOrder.pay("OpeatorA");

        // Console.WriteLine("==================");// Order virtualOrder = new Order(OrderState.Created);// virtualOrder.isVirtualOrder = true;// virtualOrder.pay("OpeatorB");// Console.WriteLine("==================");// Order paidOrder = new Order(OrderState.Paid);// paidOrder.ship();// Console.WriteLine("==================");// Order shippedOrder = new Order(OrderState.Shipped);// shippedOrder.ship();//导出 graphviz 流程图(.dot文件)//最好使用绑定状态机最开始的state对象来导出,这样流程图看起来更加漂亮, 当然也可以任意状态的状态机导出。// Console.WriteLine("==================");// Order oneOrder = new Order(OrderState.Created);// Console.WriteLine(oneOrder.exportToGraphviz());//导出 mermaid 流程图//最好使用绑定状态机最开始的state对象来导出,这样流程图看起来更加漂亮, 当然也可以任意状态的状态机导出。Console.WriteLine("==================");Order oneOrder2 = new Order(OrderState.Shipped);Console.WriteLine(oneOrder2.exportToMermaid());}
}public class Order
{public bool isVirtualOrder { get; set; }private string _operatorName;/// <summary>/// 状态机对象应该从属于业务对象/// </summary>private StateMachine<OrderState, OrderTrigger> _stateMachine;/// <summary>/// 声明一个带参数的trigger/// 状态机只允许为一个trigger 枚举值绑定一个带参数的trigger/// </summary>private StateMachine<OrderState, OrderTrigger>.TriggerWithParameters<string> _payTrigger;public Order(OrderState orderState){// 初始化状态机对象// 需要指定状态机的 initialState, 需要注意的是, 它并不是一定是整个流程中最开始的状态, 而是本业务对象的当前状态_stateMachine = new StateMachine<OrderState, OrderTrigger>(orderState);_stateMachine.OnTransitionCompleted((transition) => { Console.WriteLine($"Source:{transition.Source} Destination:{transition.Destination}"); });//非传参trigger,直接使用 trigger enum 即可//传参trigger, 必须声明为 TriggerWithParameters 类型, 参数需要通过 Fire() 函数传入, 需要在“目标State”的Configuration下通过 OnEntryFrom() 来接收参数_payTrigger = _stateMachine.SetTriggerParameters<string>(OrderTrigger.Pay);//演示使用守卫条件guard condition的状态转换,PermitIf()中的条件应该是互斥的.//最好要为守卫条件设置一个描述信息,这个描述信息将会体现到导出流程图的transition label上_stateMachine.Configure(OrderState.Created).PermitIf(OrderTrigger.Pay, OrderState.Paid, () => { return isVirtualOrder == false; }, "Non virtual order").PermitIf(OrderTrigger.Pay, OrderState.Shipped, () => { return isVirtualOrder == true; }, "Virtual order");_stateMachine.Configure(OrderState.Paid)//用来接收Trigger传参的OnEntryFrom()调用, 要放到“目标State”的Configuration下.OnEntryFrom(_payTrigger, operatorName => { _operatorName = operatorName; Console.WriteLine($"{_operatorName}"); }).Permit(OrderTrigger.Ship, OrderState.Shipped);_stateMachine.Configure(OrderState.Shipped).Permit(OrderTrigger.Confirm, OrderState.Closed);}public void pay(string operatorName){Console.WriteLine(_stateMachine.State);_stateMachine.Fire(_payTrigger, operatorName);Console.WriteLine(_stateMachine.State);}public void ship(){if (_stateMachine.CanFire(OrderTrigger.Ship)){Console.WriteLine(_stateMachine.State);_stateMachine.Fire(OrderTrigger.Ship);Console.WriteLine(_stateMachine.State);}else{Console.WriteLine($"Cannot fire {OrderTrigger.Ship} in state {_stateMachine.State}");}}/// <summary>///导出 graphviz 流程图(.dot文件), 可以使用 VS code的  Graphviz Interactive Preview 插件预览.dot 文件流程图///最好使用绑定状态机最开始的state对象来导出,这样流程图看起来更加漂亮, 当然也可以任意状态的状态机导出。/// </summary>/// <returns></returns>public string exportToGraphviz(){return Stateless.Graph.UmlDotGraph.Format(_stateMachine.GetInfo());}/// <summary>/// 将输出内容加到 markdown 的 code block 中, 形式为:/// ```mermaid      流程内容   ```/// VS code 可以安装 Markdown Preview Mermaid Support进行预览/// </summary>/// <returns></returns>public string exportToMermaid(){return Stateless.Graph.MermaidGraph.Format(_stateMachine.GetInfo());}
}public enum OrderState
{ Created, Paid, Shipped, Closed }public enum OrderTrigger
{ Pay, Ship, Confirm }

}
···

输出的graphviz流程图

输出的mermaid流程图

http://www.gsyq.cn/news/40319.html

相关文章:

  • [引]Regenerate the SAS key used in HTTP trigger flows
  • 11月4号
  • [UNIX]A Quarter Century of Unix by Peter H. Salus
  • 2025 年 11 月新风系统厂家推荐排行榜,电竞网咖酒店棋牌室KTV洗浴饭店商场办公室别墅大宅学校诊所中医馆会所美容院,商用家用极寒地区全热交换新风系统公司推荐
  • 2025 年 11 月新风系统厂家推荐排行榜,电竞网咖酒店棋牌室KTV洗浴饭店商场办公室别墅大宅学校诊所中医馆会所美容院,商用家用极寒地区全热交换系统公司精选
  • 2025 年 11 月新风系统厂家推荐排行榜,电竞网咖酒店棋牌室KTV洗浴饭店商场办公室别墅大宅学校诊所中医馆会所美容院,商用家用全热交换极寒地区适用
  • WPF的更新通知
  • 【电子工程师の设备】用于拆焊PCB的热风枪的品牌
  • 怎么设计一个好的Selenium/Appium 自动化框架? 需要考虑哪些问题
  • AIChatManager 应用功能总结
  • 结构体对齐
  • [OLAP] 技术选型对比:Clickhouse vs Doris
  • 计算天数
  • React 中 useCallback 的基本使用和原理解析
  • SpringCloud和K8s实现的微服务各有什么优缺点
  • 2025.11.4总结
  • 2025 年 11 月 EVA 厂家推荐排行榜,eva塑料,eva板材,eva卷材,eva发泡材料,eva橡塑制品公司推荐
  • 20251104 正睿
  • swagger-typescript-api
  • 2025 年 11 月电线电缆厂家推荐排行榜,国标电线电缆,中缆电线电缆,工程电线电缆,环保电线电缆,家用电线电缆,工业电线电缆,光伏电线电缆,耐火电线电缆公司推荐
  • HAL库DMA框架
  • 2025 年 11 月电线电缆厂家推荐排行榜,电力电缆,控制电缆,通信电缆,阻燃电缆,高压电缆公司推荐
  • 2025 年 11 月回信器厂家推荐排行榜,隔爆回信器,阀门回信器,防爆回信器,限位开关回信器,气动阀回信器,气动回信器公司推荐
  • 数据分析流程
  • 2025 年 11 月锅炉厂家推荐排行榜,有机热载体锅炉,导热油锅炉,生物质锅炉,蒸汽锅炉,燃天然气锅炉,热水锅炉公司推荐
  • 9.22 未完成的情感投射
  • 2025 年 11 月电磁阀厂家推荐排行榜,高压电磁阀,防爆电磁阀,比例电磁阀,汽车电磁阀,ABS电磁阀,ESP电磁阀,车用ESC电磁阀公司推荐
  • 请求库的封装
  • 用户登录系统
  • Java 内存模型(JMM)中 volatile 的作用与限制