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 方法中执行以下步骤,确保状态转换安全可靠:
验证转换:检查是否允许从当前状态切换到新状态(使用 StateValidator)。如果不允许,抛出异常。举例:试图从 Completed 回退到 Processing 会失败,因为规则不允许逆转。
退出旧状态:如果有旧状态,调用其 Exit 方法执行清理工作。场景:退出 Processing 时,记录日志或释放资源。
更新状态:将上下文的 CurrentState 设置为新状态。
持久化变更:调用 PersistStateAsync 保存到数据库或其他存储。如果失败,抛出异常。详细举例:在订单系统中,这步会更新数据库中的订单记录,确保即使系统重启,状态也不会丢失。
进入新状态:调用新状态的 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: 初始版本