Aegis.Toolkit.StateMachine

概述

Aegis.Toolkit.StateMachine 是 Aegis 框架中的状态机组件,用于管理基于枚举的状态转换。它提供了一个灵活的状态机实现,支持状态验证、处理器的进入/退出逻辑以及持久化操作。该组件适用于需要跟踪和管理对象生命周期状态的场景,如订单处理、工作流等。

主要特性

  • 基于枚举的状态定义
  • 可配置的状态转换规则
  • 支持状态进入/退出处理器
  • 抽象持久化方法,便于集成数据库
  • 集成依赖注入

支持版本

  • NuGet 包:Aegis.Toolkit.StateMachine (版本 >= 1.0.0)
  • .NET 框架:.NET 6.0 或更高

如何引入

1. Component.deps.json 配置

在项目的 component.deps.json 文件中添加依赖:

{
  "Components": {
    "Services": [ "Logging", "Swagger", "IdGenerator.SnowflakeId", "BusinessServices", "RequestValidation", "EventBus", "Jobs", "Toolkit.StateMachine" ],
    "Middlewares": [ "Swagger" ]
  }
}

2. NuGet 安装

使用 NuGet 包管理器安装:

Install-Package Aegis.Toolkit.StateMachine

如何使用

定义状态枚举

public enum OrderState
{
    Pending,
    Processing,
    Completed,
    Cancelled
}
  • 说明:我们用枚举来定义状态,就好像给订单贴标签一样,确保只有有限的几种状态可选,这样代码更安全,不会乱填状态。比如,在电商系统中,订单从 待处理 (Pending) 开始,用户下单后进入 处理中 (Processing),打包发货后变为 完成 (Completed),如果用户取消则转为 取消 (Cancelled)。这种方式防止了无效状态如'未知'的出现。

定义状态上下文

继承 StateContext

public class OrderContext : StateContext<OrderState>
{
    public int OrderId { get; set; }
    // 其他上下文数据
}
  • 说明:这个上下文就像一个包裹,里面装着 当前状态 和相关数据,比如订单ID。它帮助我们在切换状态时携带必要的信息,就好像在处理订单时,需要知道订单号来更新数据库、发送通知等。举例:当订单从 Pending 转为 Processing 时,上下文可以携带用户ID来触发邮件通知。

实现状态机

继承 BaseStateMachine

public class OrderStateMachine : BaseStateMachine<OrderState, OrderContext>
{
    public OrderStateMachine(StateValidator<OrderState> validator, StateHandlerManager<OrderState> handlerManager)
        : base(validator, handlerManager)
    {
    }

    protected override async Task<bool> PersistStateAsync(OrderContext context)
    {
        // 实现数据库持久化,例如使用 FreeSQL
        // 返回 true 如果持久化成功
        return true;
    }
}
  • 说明:状态机就像一个 交通警察,控制状态怎么变。这里你需要实现 PersistStateAsync 方法,比如把新状态存到数据库中,确保变化被记录下来。场景:用户下单后,系统调用状态机更新为 Processing,并通过此方法保存到数据库,如果保存失败则回滚。

配置状态转换规则

var transitions = new Dictionary<OrderState, OrderState[]>
{
    { OrderState.Pending, new[] { OrderState.Processing, OrderState.Cancelled } },
    { OrderState.Processing, new[] { OrderState.Completed } }
};
var validator = new StateValidator<OrderState>(transitions, new[] { OrderState.Pending });
  • 说明:这个验证器设定 规则,比如订单从 待处理 只能去 处理中取消,不能直接跳到 完成。第一个参数是转换地图,第二个是起始允许的状态,就像游戏规则,防止无效操作。详细举例:如果尝试从 Pending 直接到 Completed,验证器会抛出错误,类似于不允许棋子越过障碍直接吃王。

注册状态处理器

实现 IStateHandler

public class ProcessingHandler : IStateHandler<OrderState>
{
    public OrderState State => OrderState.Processing;

    public void Enter(StateContext<OrderState> context, OrderState? oldState)
    {
        // 进入处理逻辑
    }

    public void Exit(StateContext<OrderState> context)
    {
        // 退出处理逻辑
    }
}

然后在 StateHandlerManager 中注册。

  • 说明:处理器就是在状态切换时做额外的事,比如进入 处理中 时发邮件通知用户。就像 门卫,进门和出门时检查一下。场景:进入 Processing 时,Enter 方法可以扣除库存、通知仓库打包;退出时,Exit 方法记录日志。

应用状态变更

var context = new OrderContext { CurrentState = OrderState.Pending };
var stateMachine = new OrderStateMachine(validator, handlerManager);
await stateMachine.ApplyStateAsync(context, OrderState.Processing);
  • 说明:调用这个方法就像按下 开关,它会检查规则、做退出/进入动作、保存状态。全自动处理订单从一个阶段到下一个。完整流程:系统接收到支付确认,调用 ApplyStateAsync 从 Pending 到 Processing,内部验证通过、执行处理器、持久化成功后更新状态。

状态机处理流程

状态机在 ApplyStateAsync 方法中执行以下步骤,确保状态转换安全可靠:

  1. 验证转换:检查是否允许从当前状态切换到新状态(使用 StateValidator)。如果不允许,抛出异常。举例:试图从 Completed 回退到 Processing 会失败,因为规则不允许逆转。

  2. 退出旧状态:如果有旧状态,调用其 Exit 方法执行清理工作。场景:退出 Processing 时,记录日志或释放资源。

  3. 更新状态:将上下文的 CurrentState 设置为新状态。

  4. 持久化变更:调用 PersistStateAsync 保存到数据库或其他存储。如果失败,抛出异常。详细举例:在订单系统中,这步会更新数据库中的订单记录,确保即使系统重启,状态也不会丢失。

  5. 进入新状态:调用新状态的 Enter 方法执行初始化工作。场景:进入 Completed 时,发送完成通知给用户并更新统计数据。

这个流程就像一个有序的装配线,每个步骤都确保一切顺利进行。

如何扩展

扩展状态处理器

实现 IStateHandler 接口,为特定状态添加自定义进入/退出逻辑。

示例:

public class CustomHandler : IStateHandler<OrderState>
{
    public OrderState State => OrderState.Completed;

    public void Enter(StateContext<OrderState> context, OrderState? oldState)
    {
        // 自定义进入逻辑
    }

    public void Exit(StateContext<OrderState> context)
    {
        // 自定义退出逻辑
    }
}

注册到 StateHandlerManager:

handlerManager.Register(new CustomHandler());

扩展状态机

继承 BaseStateMachine 并重写 PersistStateAsync 以实现自定义持久化逻辑。

扩展验证器

如果需要更复杂的验证规则,可以继承或替换 StateValidator。

常见问题

  • Q: 如何处理初始状态? A: 使用 CanInitialTransition 方法检查。
  • Q: 持久化失败如何处理? A: 方法会抛出 InvalidOperationException。

最后更新日期:2023-10-01

变更日志:

  • v1.0: 初始版本

results matching ""

    No results matching ""