跳到主要内容
版本:3.0.0

状态机工具(Aegis.Toolkit.StateMachine)

Aegis.Toolkit.StateMachine 用来把复杂状态流转从业务代码里拆出来。它提供状态上下文、状态验证器、状态处理器和状态机基类,适合把“哪些状态能转、进入某状态要做什么、退出某状态要做什么”统一收口。

组件概览

字段说明
组件名称状态机工具
真实类库Aegis.Toolkit.StateMachine
组件定位通用状态机工具包
引入方式安装 NuGet,并在 Component.deps.jsonServices 中启用 Toolkit.StateMachine
组件声明Toolkit.StateMachine
核心能力StateContext<TState>StateValidator<TState>StateHandlerManager<TState, TContext>BaseStateMachine<TState, TContext>
典型配套Services、Repository

什么时候要用它

适合场景:

  • 业务存在明确的状态流转图
  • 状态切换前后有校验和副作用
  • 你希望把状态流转规则从 Service 里拆出来

最小可运行路径

第一步:启用 Toolkit.StateMachine

{
"Components": {
"Services": [
"Toolkit.StateMachine"
],
"Middlewares": []
}
}

第二步:定义状态枚举

public enum OrderState
{
Pending,
Processing,
Completed,
Cancelled
}

第三步:定义状态上下文

public class OrderContext : StateContext<OrderState>
{
public int OrderId { get; set; }
}

第四步:定义状态处理器

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

public ApplyStateResult CanTransition(OrderContext context, OrderState? newState)
{
return new ApplyStateResult
{
IsSuccess = true,
Code = 200,
Message = "OK"
};
}

public void Enter(OrderContext context, OrderState? oldState)
{
}

public void Exit(OrderContext context)
{
}
}

第五步:定义状态机

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

protected override Task<bool> PersistStateAsync(OrderContext context)
{
return Task.FromResult(true);
}
}

第六步:应用状态变更

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 });

var context = new OrderContext
{
CurrentState = OrderState.Pending,
OrderId = 1001
};

await stateMachine.ApplyStateAsync(context, OrderState.Processing);

这组类型分别负责什么

类型负责什么
StateContext<TState>携带当前状态和上下文数据
StateValidator<TState>负责状态流转规则校验
IStateHandler<TState, TContext>负责某个状态的进入、退出和转移检查
StateHandlerManager<TState, TContext>收集和分发状态处理器
BaseStateMachine<TState, TContext>统一执行“校验 -> 退出 -> 持久化 -> 进入”流程

状态机实际执行流程

ApplyStateAsync(...) 的主流程可以理解成:

  1. 先检查当前状态能不能转到目标状态
  2. 旧状态处理器先执行 Exit(...)
  3. 旧状态处理器再做 CanTransition(...)
  4. 更新 CurrentState
  5. 调用 PersistStateAsync(...) 持久化
  6. 新状态处理器执行 Enter(...)

这意味着:
真正的数据库保存逻辑,应该写在你自己的 PersistStateAsync(...) 里。

边界与限制

当前接口签名是双泛型

业务处理器应实现的是:

IStateHandler<TState, TContext>

而不是旧写法里的单泛型版本。

状态机本身不替你做持久化

BaseStateMachine 只约束流程,不直接落库。
状态保存仍然由你自己的业务状态机实现。

更推荐在 Service 层组织状态机调用

状态机负责“状态怎么变”,Service 负责“什么时候变、为什么变、和哪些业务动作一起变”。

接入后怎么确认已经生效

可以这样确认:

  • Toolkit.StateMachine 启用后没有装配异常
  • 调用 ApplyStateAsync(...) 时,非法状态能被挡住
  • 合法状态能更新并进入对应处理器

常见问题

为什么状态机里还要自己写 PersistStateAsync(...)

因为当前工具包只提供统一流程,不替业务决定如何保存状态。

为什么处理器没有被自动发现

当前更稳的口径是:把状态机相关类型作为业务内显式组织的工具来用,不要依赖模糊的自动发现预期。

状态机应该写在 Controller 吗

不建议。
更推荐放在 Services 或领域层里。

配套阅读