这是一个状态自动下推机的功能库。
依赖项
- Reface,这是一个基础库,由 .NetStandard2.0 开发
对某个目标事物,发生不动行为后,状态就会发生变化。 例如:
对一个文档 保存 后,它变成了 草稿 状态。 再对 草稿 状态的文档 审核 以后,会变成 已审核 状态, 若对 草稿 状态的文档 删除 ,则会变成 删除 状态, 当文档已经是 已审核 状态时,不再允许进行 删除 操作。
状态机中的两个概念,一个是 状态 一个是 行为,从上面的例子来看
状态是
- 草稿
- 已审核
- 删除
行为是
- 保存
- 审核
- 删除
简单的来说,行为就是,在某个状态时,到某个状态去。
使用 Reface.StateMachine 你可以简单的定义一个状态转移的整个过程。 当你要使用它时,只要使用 Machine.Push(Action) 就行了。
使用 Nuget 搜索 Reface.StateMachine 即可, 由于 Reface.StateMachine 中有一些使用是使用 .NetStandard 开发的,所以请保证你的 .Net Framework 版本最低是 4.6.1
> Install-Package Reface.StateMachine -Version 1.0.2
首先,你需要创建两个枚举类型,分别表示 States 和 Actions ,如:
public enum DocumentStates
{
Default,
Draft,
Checked,
Deleted
}
public enum DocumentActions
{
Save,
Check,
Delete
}
再使用 CodeStateMachineBuilder<TState, Code> 构建一个 Machine , CodeStateMachineBuilder 被设计成了使用 链式 语句声明的风格, 可以参考下面的代码。
var builder = new CodeStateMachineBuilder<DocumentStates, DocumentActions>();
builder
.StartWith(DocumentStates.Default) // 默认的状态
.From(DocumentStates.Default)
.When(DocumentActions.Save).To(DocumentStates.Draft)
.From(DocumentState.Draft)
.When(DocumentActions.Check).To(DocumentStates.Checked)
.When(DocumentActions.Delete).To(DocumentStates.Deleted);
var machine = builder.Build();
machine.Push(DocumentActions.Save);
machine.Push(DocumentActions.Check);
// 此时的状态会移动到 Checked 上
我们使用 Machine.Push(Actions) 的主要目的是要让状态发生变化。 我们可以使用 Machine 上的事件来监听状态发生的变化。
事件的监听有两种方法:
Pushed 事件
当任意 Action 完成了对状态的转移后,就会触发该事件,该事件会通知此时的 Push 是执行的哪个行为,从哪个状态移动到了哪个状态。
machine.Pushed += (sender, e) =>
{
//sender is machine
//e.OldState
//e.NewState
//e.Action
};
状态 事件
Pushed 事件面向所有的状态移动, 因此我们设计了 状态 事件和监听,可以针对某个状态监听其离开和进入。
var listener = machine.GetListener(DocumentStates.Draft);
listener.Entered += (sender, e) =>
{
// 刚进入这个状态时的事件
};
listener.Leaving += (sender, e) =>
{
// 正准备离开这个状态时的事件
};
在设计状态机时,可以指定一些停机状态。 当状态机进入停机状态后,可以发生停机事件。
设置停机状态,可以通过 [StopState] 和 Build.StopWith 两种途径设置。
在代码设计阶段,我们往往不能一次性将复杂的状态转移写好。 虽然我们提供了 链式 定义的方法,但是面对一长段的状态转移定义,修改和维护往往比较困难。 因此,我们设计了通过配置文件,更直观的定义状态转移过程,而不需要使用链式声明法。
这是一种使用二维表格定义状态转移的方法,但是为了减少对第三方库的依赖,没有使用 Excel 格式,而使用了 Csv 文件格式。
以上述文件转移做为例子,配置文件应该像下面这个样子
Save | Check | Delete | |
---|---|---|---|
Default | Draft | ||
Draft | Checked | Deleted | |
Deleted |
第一行第一列为空
第一行第一列为空
第一行第一列为空
(重要的事情说三次!)
第一行是所有的行为, 第一列是所有的状态
在 行 与 列 的交接入,表示在这个状态下触发此行为时,进入的下一个状态。
状态与行为的名称,必须与你的枚举类型中的项名称一致 !!!
配置文件定义好后,就可以直接利用这个 csv 文件产生 machine 了。
var machine = CsvStateMachineBuilder<DocumentTests, DocumentActions>.FromFile(".\1.csv").Build();
一行代码就OK了。 当然了,还有一个小细节需要注意一下: 我们需要设置状态机的默认状态, 使用 [StartState] 特征可以在枚举类型上设定默认的状态,这个特征,只有在使用 csv 生成的状态机时才会被使用到。
public enum DocumentTest
{
[StartState]
Default,
Draft,
Checked,
Deleted
}
相关链接