Stateless是一個基於C#創建狀態機的簡單庫
.Net輕量狀態機Stateless
很多業務系統開發中,不可避免的會出現狀態變化,通常采用的情形可能是使用工作流去完成,但是對於簡單場景下,用工作流有點大財小用感覺,比如訂單業務中,訂單狀態的變更,涉及到的狀態量不是很多,即使通過簡單的if-else也能足夠使用,甚至是用上switch去減少if-else的使用,都是可以的,盡管這會喪失某些東西。為更好的優化整個流程,此時會考慮到使用狀態模式來解決一些問題。
一、狀態模式與狀態機
1、狀態模式:"允許一個對象在其內部狀態改變時改變它的行為。對象看起來似乎修改了它所屬的類 "。 (State Pattern: "Allow an object to alter its behavior when its internal state changes. The object will appear to change its class ".)
2、狀態機:"依照指定的狀態流程圖,根據當前執行的動作,將當前狀態按照預定的條件變更到新的狀態 "。
//初始化狀態機 var phoneCall = new StateMachine<State, Trigger>(State.OffHook); //流程配置 phoneCall.Configure(State.OffHook) .Permit(Trigger.CallDialled, State.Ringing); phoneCall.Configure(State.Ringing) .Permit(Trigger.CallConnected, State.Connected); phoneCall.Configure(State.Connected) .OnEntry(() => StartCallTimer()) .OnExit(() => StopCallTimer()) .Permit(Trigger.LeftMessage, State.OffHook) .Permit(Trigger.PlacedOnHold, State.OnHold); // ... //觸發行為 phoneCall.Fire(Trigger.CallDialled); Assert.AreEqual(State.Ringing, phoneCall.Stat
1、功能特性
2、分層狀態
phoneCall.Configure(State.OnHold) .SubstateOf(State.Connected) .Permit(Trigger.TakenOffHold, State.Connected) .Permit(Trigger.PhoneHurledAgainstWall, State.PhoneDestroyed);
3、狀態的進入和退出事件
4、外部狀態存儲
var stateMachine = new StateMachine<State, Trigger>( () => myState.Value, s => myState.Value = s );
5、內省
public IEnumerable<TTrigger> PermittedTriggers { get { return GetPermittedTriggers(); } } //返回StateMachineInfo對象,包含狀態及觸發器列表。 _machine.GetInfo();
6、衛語句
phoneCall.Configure(State.OffHook) .PermitIf(Trigger.CallDialled, State.Ringing, () => IsValidNumber) .PermitIf(Trigger.CallDialled, State.Beeping, () => !IsValidNumber)
7、參數化觸發器
var assignTrigger = stateMachine.SetTriggerParameters<string>(Trigger.Assign); stateMachine.Configure(State.Assigned) .OnEntryFrom(assignTrigger, email => OnAssigned(email)); stateMachine.Fire(assignTrigger, "joe@example.com");
8、忽視轉換和重入狀態
phoneCall.Configure(State.Connected) .Ignore(Trigger.CallDialled);
另外,一個狀態能夠使用PermitReentry方法配置為重復進入(從本狀態到本狀態),entry和exit事件也會被再次觸發。
stateMachine.Configure(State.Assigned) .PermitReentry(Trigger.Assigned) .OnEntry(() => SendEmailToAssignee());
默認情形下,必須明確忽略哪些觸發器。 當未配置的觸發器被觸發時默認是拋出異常,可以通過使用OnUnhandledTrigger配置狀態機覆寫處理異常情形。
stateMachine.OnUnhandledTrigger((state, trigger) => { });
9、導出DOT格式圖
phoneCall.Configure(State.OffHook) .PermitIf(Trigger.CallDialled, State.Ringing, IsValidNumber); string graph = UmlDotGraph.Format(phoneCall.GetInfo());
UmlDotGraph.Format()方法返回代表狀態機的字符串,使用DOT graph語言格式。這個可以被支持DOT graph語言的工具渲染。像graphviz.org
10、異步觸發
stateMachine.Configure(State.Assigned) .OnEntryAsync(async () => await SendEmailToAssignee()); await stateMachine.FireAsync(Trigger.Assigned);
至此,對於狀態機Stateless的功能差不多了解完畢了,開始將狀態機融入到項目中實際使用起來,也已經加入到日程中。