转换到目标状态并触发转换和状态之间的状态机?
Statemachine that transitions to target state and fires transitions and states between?
我最近使用了 Stateless 状态机。我可以像这样定义转换等规则:
stateMachine.Configure(State.Unknown)
.Permit(Trigger.StartApplication, State.Initialized)
.OnEntry(this.DoBeforeTransition)
.OnExit(this.DoAfterTransition);
stateMachine.Configure(State.Initialized)
.Permit(Trigger.CheckSomething, State.SomethingChecked)
.OnEntry(this.DoBeforeTransition)
.OnExit(this.DoAfterTransition);
然后您就可以触发触发器来更改状态。但是,如果您想进入特定状态,则需要知道当前状态以及下一个状态。因此,状态机的 "client" 需要知道如果没有定义 直接转换 如何达到特定状态。是否有可能调用 "goto " 之类的东西,并且机器会自己触发所有必需的触发器?
您可以这样做,因为每个州只有一个 "Permit"。如果您有多个 "Permit",则您无法在工作流程中自动移动(必须有某种原因让您选择一个 Permit/Trigger 而不是另一个)。当我说你 "cannot" 时,这不是技术上的,而是实际上的。
下面是在工作流中自动移动的示例。
using Stateless;
using System;
using System.Runtime.CompilerServices;
namespace MyExample.BAL.WorkFlows
{
public class TelephoneCallWorkFlow
{
private static volatile StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum> SingletonInstance;
public StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum> Instance
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
if (SingletonInstance == null)
{
SingletonInstance = new StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum>(TelephoneCallStateEnum.OffHook);
SingletonInstance.Configure(TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.CallDialed, TelephoneCallStateEnum.Ringing);
SingletonInstance.Configure(TelephoneCallStateEnum.Ringing)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.CallConnected, TelephoneCallStateEnum.Connected);
SingletonInstance.Configure(TelephoneCallStateEnum.Connected)
//.OnEntry(t => StartCallTimer())
//.OnExit(t => StopCallTimer())
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.LeftMessage, TelephoneCallStateEnum.OffHook)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.PlacedOnHold, TelephoneCallStateEnum.OnHold)
;
SingletonInstance.Configure(TelephoneCallStateEnum.OnHold)
//removing so there is only one valid path workflow//.SubstateOf(TelephoneCallStateEnum.Connected)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.TakenOffHold, TelephoneCallStateEnum.Connected)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.PhoneHurledAgainstWall, TelephoneCallStateEnum.PhoneDestroyed)
;
}
return SingletonInstance;
}
}
public void Fire(TelephoneCallTriggerEnum trigger)
{
Console.WriteLine("............[Firing:] {0}", trigger);
this.Instance.Fire(trigger);
}
}
}
public enum TelephoneCallStateEnum
{
OffHook,
Ringing,
Connected,
OnHold,
PhoneDestroyed
}
public enum TelephoneCallTriggerEnum
{
CallDialed,
HungUp,
CallConnected,
LeftMessage,
PlacedOnHold,
TakenOffHold,
PhoneHurledAgainstWall
}
现在是 "auto-move" 技巧。
TelephoneCallWorkFlow tcwf1 = new TelephoneCallWorkFlow();
IEnumerable<TelephoneCallTriggerEnum> myPermittedTriggers = tcwf1.Instance.PermittedTriggers;
while (null != myPermittedTriggers && myPermittedTriggers.Count() > 0)
{
if (myPermittedTriggers.Count() > 1)
{
throw new ArgumentOutOfRangeException("You cannot auto-move the workflow when there's more than one trigger");
}
TelephoneCallTriggerEnum nextTrigger = myPermittedTriggers.FirstOrDefault();
Console.WriteLine("About to call the 'next' trigger: --> {0}", nextTrigger);
tcwf1.Fire(nextTrigger);
Console.WriteLine("CurrentState: --> {0}", tcwf1.Instance.State);
myPermittedTriggers = tcwf1.Instance.PermittedTriggers;
}
你基本上获得了 PermittedTriggers,并获得了第一个(并且为了自动移动工作,每个状态应该只有一个 Permitted-Trigger)......然后调用该触发器。
同样,实际上(不是技术上)你只会在每个州有一个 Permit/Trigger 的情况下这样做。因此,如果超过 1 个,为什么我有一个例外。如果超过 1 个,你可以 "get the first",这没有任何意义。
我最近使用了 Stateless 状态机。我可以像这样定义转换等规则:
stateMachine.Configure(State.Unknown)
.Permit(Trigger.StartApplication, State.Initialized)
.OnEntry(this.DoBeforeTransition)
.OnExit(this.DoAfterTransition);
stateMachine.Configure(State.Initialized)
.Permit(Trigger.CheckSomething, State.SomethingChecked)
.OnEntry(this.DoBeforeTransition)
.OnExit(this.DoAfterTransition);
然后您就可以触发触发器来更改状态。但是,如果您想进入特定状态,则需要知道当前状态以及下一个状态。因此,状态机的 "client" 需要知道如果没有定义 直接转换 如何达到特定状态。是否有可能调用 "goto " 之类的东西,并且机器会自己触发所有必需的触发器?
您可以这样做,因为每个州只有一个 "Permit"。如果您有多个 "Permit",则您无法在工作流程中自动移动(必须有某种原因让您选择一个 Permit/Trigger 而不是另一个)。当我说你 "cannot" 时,这不是技术上的,而是实际上的。
下面是在工作流中自动移动的示例。
using Stateless;
using System;
using System.Runtime.CompilerServices;
namespace MyExample.BAL.WorkFlows
{
public class TelephoneCallWorkFlow
{
private static volatile StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum> SingletonInstance;
public StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum> Instance
{
[MethodImpl(MethodImplOptions.Synchronized)]
get
{
if (SingletonInstance == null)
{
SingletonInstance = new StateMachine<TelephoneCallStateEnum, TelephoneCallTriggerEnum>(TelephoneCallStateEnum.OffHook);
SingletonInstance.Configure(TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.CallDialed, TelephoneCallStateEnum.Ringing);
SingletonInstance.Configure(TelephoneCallStateEnum.Ringing)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.CallConnected, TelephoneCallStateEnum.Connected);
SingletonInstance.Configure(TelephoneCallStateEnum.Connected)
//.OnEntry(t => StartCallTimer())
//.OnExit(t => StopCallTimer())
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.LeftMessage, TelephoneCallStateEnum.OffHook)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.PlacedOnHold, TelephoneCallStateEnum.OnHold)
;
SingletonInstance.Configure(TelephoneCallStateEnum.OnHold)
//removing so there is only one valid path workflow//.SubstateOf(TelephoneCallStateEnum.Connected)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.TakenOffHold, TelephoneCallStateEnum.Connected)
//removing so there is only one valid path workflow//.Permit(TelephoneCallTriggerEnum.HungUp, TelephoneCallStateEnum.OffHook)
.Permit(TelephoneCallTriggerEnum.PhoneHurledAgainstWall, TelephoneCallStateEnum.PhoneDestroyed)
;
}
return SingletonInstance;
}
}
public void Fire(TelephoneCallTriggerEnum trigger)
{
Console.WriteLine("............[Firing:] {0}", trigger);
this.Instance.Fire(trigger);
}
}
}
public enum TelephoneCallStateEnum
{
OffHook,
Ringing,
Connected,
OnHold,
PhoneDestroyed
}
public enum TelephoneCallTriggerEnum
{
CallDialed,
HungUp,
CallConnected,
LeftMessage,
PlacedOnHold,
TakenOffHold,
PhoneHurledAgainstWall
}
现在是 "auto-move" 技巧。
TelephoneCallWorkFlow tcwf1 = new TelephoneCallWorkFlow();
IEnumerable<TelephoneCallTriggerEnum> myPermittedTriggers = tcwf1.Instance.PermittedTriggers;
while (null != myPermittedTriggers && myPermittedTriggers.Count() > 0)
{
if (myPermittedTriggers.Count() > 1)
{
throw new ArgumentOutOfRangeException("You cannot auto-move the workflow when there's more than one trigger");
}
TelephoneCallTriggerEnum nextTrigger = myPermittedTriggers.FirstOrDefault();
Console.WriteLine("About to call the 'next' trigger: --> {0}", nextTrigger);
tcwf1.Fire(nextTrigger);
Console.WriteLine("CurrentState: --> {0}", tcwf1.Instance.State);
myPermittedTriggers = tcwf1.Instance.PermittedTriggers;
}
你基本上获得了 PermittedTriggers,并获得了第一个(并且为了自动移动工作,每个状态应该只有一个 Permitted-Trigger)......然后调用该触发器。
同样,实际上(不是技术上)你只会在每个州有一个 Permit/Trigger 的情况下这样做。因此,如果超过 1 个,为什么我有一个例外。如果超过 1 个,你可以 "get the first",这没有任何意义。