剑客
关注科技互联网

Stateless 3.0——.NET Core上的状态机库

Stateless是一个基于C#,创建状态机的简单库,最新版本支持.NET Core 1.0。其实现方式并不是通过.NET Core,而是通过写入.NET Standard实现的。就像Android平台上API级别抽象出许多底层版本的Android,.NET Standard是一组所有.NET平台上都必须实现的API。

更令开发者高兴的是,Stateless 3.0基于.NET Standard 1.0编写,是一个被广泛使用和最具兼容性的标准版本,几乎可以运行在任何地方,从Windows平台上的.NET Framework、.NET Core到Mac,和Windows应用商店以及所有的移动平台。

特征:

支持大多数标准状态机构造:

  • 支持任何.NET类型(数字、字符串、枚举等)状态和触发器;
  • 分层状态;
  • 状态的进入/退出事件;
  • Guard子句以支持条件转换;
  • 内省。

与此同时,还提供一些有用的扩展:

  • 支持外部的状态存储(例如:由ORM跟踪属性);
  • 参数化触发器;
  • 可重入状态;
  • 支持DOT格式图导出。

使用Stateless创建一个简单的状态机

下面来看几个代码示例。先描述一些有限状态,例如一个枚举类型和一些用于改变状态的有限“触发器”,就像开发一样,来启动和关闭状态以及进行触发器切换。

另一个更加实用的例子是Bug Tracker,源码在GitHub上。下面是一个Bug和触发器状态,引起状态改变:

enum State { Open, Assigned, Deferred, Resolved, Closed }
enum Trigger { Assign, Defer, Resolve, Close }

下面进行状态初始化,定义StateMachine,如果你愿意,可以在状态触发时传递参数。例如,如果你使用Assign触发Bug,可以传入“Scott”,这样该Bug就会进入Assigned状态——分配给Scott。

State _state = State.Open;
StateMachine<State, Trigger> _machine;
StateMachine<State, Trigger>.TriggerWithParameters<string> _assignTrigger;

string _title;
string _assignee;

在这个例子中,Bug构造函数使用一个流畅接口的状态机,该接口读得相当不错。

public Bug(string title)
{
    _title = title;

    _machine = new StateMachine<State, Trigger>(() => _state, s => _state = s);

    _assignTrigger = _machine.SetTriggerParameters<string>(Trigger.Assign);

    _machine.Configure(State.Open)
        .Permit(Trigger.Assign, State.Assigned);

    _machine.Configure(State.Assigned)
        .SubstateOf(State.Open)
        .OnEntryFrom(_assignTrigger, assignee => OnAssigned(assignee))
        .PermitReentry(Trigger.Assign)
        .Permit(Trigger.Close, State.Closed)
        .Permit(Trigger.Defer, State.Deferred)
        .OnExit(() => OnDeassigned());

    _machine.Configure(State.Deferred)
        .OnEntry(() => _assignee = null)
        .Permit(Trigger.Assign, State.Assigned);
}

例如,当状态打开时,可以进行分配,但是,由于它是被写入的(你可以改变),所以你无法关闭一个处于开放状态并且没有分配的Bug。

当Bug被分配时,你可以关闭,延迟或重新分配。这是PermitReentry()。另外,注意一下,Assigned是一个子状态。

你可以有状态地改变触发事件,这些事件可以根据您的个人设置采取行动。

void OnAssigned(string assignee)
{
    if (_assignee != null && assignee != _assignee)
        SendEmailToAssignee("Don't forget to help the new employee.");

    _assignee = assignee;
    SendEmailToAssignee("You own it.");
}

void OnDeassigned()
{
    SendEmailToAssignee("You're off the hook.");
}

void SendEmailToAssignee(string message)
{
    Console.WriteLine("{0}, RE {1}: {2}", _assignee, _title, message);
}

拥有一个好的状态机库,例如Stateless,可以让你快速地模拟状态。能否分享一下,你在项目中使用的状态机是什么样子的?

原文: Stateless 3.0 – A State Machine library for .NET Core

作者:Scott Hanselman 翻译:Daisy 责编:仲培艺

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址