很多业务系统开发中,不可避免的会出现状态变化,通常采用的情形可能是使用工作流去完成,但是对于简单场景下,用工作流有点大财小用感觉,比如订单业务中,订单状态的变更,涉及到的状态量不是很多,即使通过简单的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、状态机:"依照指定的状态流程图,根据当前执行的动作,将当前状态按照预定的条件变更到新的状态 "。
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的功能差不多了解完毕了,开始将状态机融入到项目中实际使用起来,也已经加入到日程中。
原文链接:https://www.cnblogs.com/CKExp/p/11564882.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com