我遇到了无状态,一个基于Simple State Machine for Boo的分层状态机框架,但是使用C#3.0进行配置
它易于配置和使用,我很快就会使用它.
但我只是想知道是否
我有一些相当简单的状态需求(目前).我想我想使用Stateless api 对这些进行建模.(但我对国家机器并不是很了解,所以我错了.)
但是我被卷入了术语(特别是状态和触发器)
这是一个例子:我有一个订单类.它设置有几个状态.它们是:新的,填充的,装运的,已完成的,已取消的.
我想要的一些简单的状态规则是允许这些状态转换:
那么我在这里被绊倒的是我的"触发器"是什么?
如果需要更具体的示例,请说我想要一个这样的方法:
public bool UpdateOrderStatus(int OrderId, OrderStatusEnum NewOrderStatus)
Run Code Online (Sandbox Code Playgroud)
如果状态更新成功,则返回true.如何设置和使用Stateless来实现这一目标?
我想在我的代码中使用http://code.google.com/p/stateless将功能与其依赖项分开.我没有找到任何高级的用法示例,所以这个问题是关于无状态框架的最佳实践.
我有以下配置(这只是一个例子,只有一个功能状态):
var stateMachine = new StateMachine(State.Stopped);
stateMachine.Configure(State.Stopped)
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.GenerateMachineData);
stateMachine.Configure(State.GenerateMachineData)
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.Finished);
public enum State
{
Stopped,
GenerateMachineData,
Finished,
Error
}
public enum Trigger
{
Succeed,
Failed
}
Run Code Online (Sandbox Code Playgroud)
那么在哪里调用实际的功能.我有以下想法,但每个都有优点和缺点:
1)在OnEntry()中设置功能以及下一次触发:
stateMachine.Configure(State.GenerateMachineData)
.OnEntry(() => {
try {
Generate();
stateMachine.Fire(Trigger.Succeed);
} catch {
stateMachine.Fire(Trigger.Error);
}
})
.Permit(Trigger.Failed, State.Error)
.Permit(Trigger.Succeed, State.Finished);
Run Code Online (Sandbox Code Playgroud)
那么如果我只是打电话
stateMachine.Fire(Trigger.Succeed);
Run Code Online (Sandbox Code Playgroud)
它最终在State.Finished或State.Error中结束
2)将状态机和功能分开,如:
__CODE__或__CODE__直接传入,因为这可能不是你想要发生的.即使他们这样做了,你仍然需要__CODE__/ __CODE__处理创建对象的错误.供应商是一种懒惰的回调,它允许一次性创建,使用和关闭实际对象,而不必进行大量的丑陋__CODE__/ __CODE__错误处理.
例如,只需查看将一个文件复制到另一个文件所需的代码(使用Guava实用程序将实际复制和流关闭代码最小化):
void DoTheStuff() …
在使用c#无状态库时,人们如何构建代码?
https://github.com/nblumhardt/stateless
我特别感兴趣的是它如何与注入的依赖关系以及正确的职责和分层方法联系起来.
我目前的结构涉及以下内容:
public class AccountWf
{
private readonly AspNetUser aspNetUser;
private enum State { Unverified, VerificationRequestSent, Verfied, Registered }
private enum Trigger { VerificationRequest, VerificationComplete, RegistrationComplete }
private readonly StateMachine<State, Trigger> machine;
public AccountWf(AspNetUser aspNetUser, AccountWfService userAccountWfService)
{
this.aspNetUser = aspNetUser;
if (aspNetUser.WorkflowState == null)
{
aspNetUser.WorkflowState = State.Unverified.ToString();
}
machine = new StateMachine<State, Trigger>(
() => (State)Enum.Parse(typeof(State), aspNetUser.WorkflowState),
s => aspNetUser.WorkflowState = s.ToString()
);
machine.Configure(State.Unverified)
.Permit(Trigger.VerificationRequest, State.VerificationRequestSent);
machine.Configure(State.VerificationRequestSent)
.OnEntry(() => userAccountWfService.SendVerificationRequest(aspNetUser))
.PermitReentry(Trigger.VerificationRequest)
.Permit(Trigger.VerificationComplete, State.Verfied);
machine.Configure(State.Verfied)
.Permit(Trigger.RegistrationComplete, State.Registered); …Run Code Online (Sandbox Code Playgroud) 我有一个项目,其中主要是线性工作流程.我正在尝试使用.NET Stateless 库充当工作流引擎/状态机.那里的例子数量有限,但我把以下代码放在一起:
private StateMachine<WorkflowStateType, WorkflowStateTrigger> stateMachine;
private StateMachine<WorkflowStateType, WorkflowStateTrigger>.TriggerWithParameters<Guid, DateTime> registrationTrigger;
private Patient patient;
public Patient RegisterPatient(DateTime dateOfBirth)
{
configureStateMachine(WorkflowState.Unregistered);
stateMachine.Fire<DateTime>(registrationTrigger, dateOfBirth);
logger.Info("State changed to: " + stateMachine.State);
return patient;
}
private void configureStateMachine(WorkflowState state)
{
stateMachine = new StateMachine<WorkflowState, WorkflowTrigger>(state);
registrationTrigger = stateMachine.SetTriggerParameters<DateTime>(WorkflowTrigger.Register);
stateMachine.Configure(WorkflowState.Unregistered)
.Permit(WorkflowTrigger.Register, WorkflowStateType.Registered);
stateMachine.Configure(WorkflowState.Registered)
.Permit(WorkflowTrigger.ScheduleSampling, WorkflowState.SamplingScheduled)
.OnEntryFrom(registrationTrigger, (dateOfBirth) => registerPatient(dateOfBirth));
}
private void registerPatient(DateTime dateOfBirth)
{
//Registration code
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我正在使用Stateless Fire()重载,它允许我传入一个触发器.这样我就可以拥有状态机进程业务逻辑,在这种情况下,代码可以注册一个新患者.
这一切都有效,但现在我想将所有状态机代码移动到另一个类中来封装它,我在这方面遇到了麻烦.我这样做的挑战是:
StateMachine对象需要您指定state,并且State是一个只能在实例化时设置的只读属性.registrationTrigger必须在状态机配置期间实例化,并且必须由调用类提供.如何克服这些项并封装状态机代码?
我想有一个登录我工作流状态转换的数据库.
使用Stateless触发日志记录的最佳位置在哪里?是否应为每个州配置进行设置:
phoneCall.Configure(State.Connected)
.OnEntry(() => StartCallTimer())
.OnEntry(() => Log());
Run Code Online (Sandbox Code Playgroud)
或者有一些方法可以为整个工作流程集中定义一次?
欢迎提供这方面的任何其他意见.
我最近一直在试验Stateless(C#中的HSM)(https://code.google.com/p/stateless/),而且我遇到了一些我不确定如何实现的东西.
假设我有以下状态:
开始.
连
读
完
我想要实现的是:当TCP连接(处于Connect状态)建立时,进入Read状态.或者,如果失败,则进入"完成"状态(它可能会返回"连接"状态并在超时后尝试新连接).
如何使用Stateless实现此自动推进功能,因为从状态内触发触发器会导致堆栈溢出异常?
干杯
我在我们的应用程序中使用无状态来实现状态机的逻辑.我们有一个AcceptedFile具有其他内部(子)状态的状态.问题是我不知道如何在我的代码中指示初始内部状态,以便当机器转移到AccptedFile状态它也会自动转换到其初始内部状态.这就是我为模拟这种行为所做的:
machine.Configure(State.AcceptedFile)
.OnEntry(() => machine.Fire(Trigger.MakeReadyForAdvertising))
.Permit(Trigger.MakeReadyForAdvertising,State.ReadyForAdvertising)
Run Code Online (Sandbox Code Playgroud)
这ReadyForAdvertising是一个内部状态.AcceptedFile这在大多数情况下工作正常,但每当我将状态机的初始状态设置为AcceptedFile这样:
var statemachine=new StateMachine<State,Trigger>(State.AcceptedFile)
...
Run Code Online (Sandbox Code Playgroud)
不会发生自动转换,因此机器将处于AcceptedFile状态而不是ReadyForAdvertising.
有没有更好的方法来实现这种行为?
我正在使用无状态框架(https://code.google.com/p/stateless/)在我的应用程序中建模有限状态机.某些状态应该执行某些逻辑,然后立即进入下一个状态.我想知道这样做的好习惯如下:
var machine = new StateMachine<State, Trigger>(State.Idle);
machine.Configure(State.StateA)
.OnEntry(() =>
{
DoSomeStuff();
_machine.Fire(Trigger.TriggerB); // move to StateB
});
Run Code Online (Sandbox Code Playgroud)
这是一个很好的FSM设计吗?如果没有,那会有什么更好的方法?我试图实现的想法是让某些状态自动将机器推进到下一个状态,而不需要等待DoSomeStuff()完成然后触发机器在下一个状态下移动的外部代码.
在我正在使用的 C# 解决方案中,应用程序逻辑的核心通过(非常好的)无状态库实现为状态机。对于应用程序显示的不同区域和功能,在许多其他类中建模了业务逻辑的其他部分,但这是推动底层应用程序状态发生主要变化的部分。
尽管每个状态转换本身都非常简单(通知事件、设置 eventArgs、侦听其他事件……)并且我在适用时使用了子状态,但对我来说它开始看起来有点太大了。我知道这不是一个精确的度量,但是如果您查看并考虑子状态,您很可能最终会发现它们本身可能是不同的状态机。
是否有一种明显的方法让我无法使用无状态构建单独的子状态机(可以这么说),将每个状态机映射到不同的类(和文件)?
我想到的第一个阻塞问题是(尤其是第二个):
在一个大的片上所有的状态变化的状态机触发事件:分裂后,每个单一的国家机器将火每个自己的触发器。所以最好有一个外观收集所有事件并为客户端重新触发它们,以便隐藏许多状态机(毕竟它们是客户端的实现细节)。
无状态子状态负责向上和向下的状态/子状态链的冒泡触发器。因此,例如对于A具有子状态的给定状态,您可以定义一个触发器(在一个地方,A配置),A无论A我们将处于哪个子状态,状态机都会离开。这如何与单独的子状态机一起工作?
长话短说:
\n\n状态机框架应该在哪里/如何确定下一个状态应该是什么什么?或者,这实际上超出了状态机的范围,状态机实际上仅用于跟踪当前状态并验证是否允许请求的转换?
\n\n背景和细节:
\n\n考虑一个简单的杂志文章发布工作流程。下图显示了对该过程的基本概念理解,我们希望将其转换为代码(在本例中使用Stateless)。它涵盖了出版的基本“快乐之路”,以及一些可能的问题:
\n\n\xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90\n\xe2\x94\x82 W \xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82\n\xe2\x94\x82 r \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 i \xe2\x94\x82 \xe2\x94\x82 Write \xe2\x97\x84\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82\n\xe2\x94\x82 t \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 e \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 r \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xbc\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80Submit\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x82\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xa4\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x8c\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x96\xbc\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 Review \xe2\x97\x84\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\xac\xe2\x94\x80\xe2\x94\x82\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x90 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\xe2\x94\x98 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82\n\xe2\x94\x82 \xe2\x94\x82 \xe2\x94\x82 …Run Code Online (Sandbox Code Playgroud) 我最近遇到了一个脏的 if-else 代码,所以我寻找了一个重构选项,并找到了state-machine作为脏if-else代码的优雅替代品的推荐。但有些事情我很难理解:看起来作为客户,我有责任将机器从一种状态转移到另一种状态。现在,如果有 2 个转换选项(取决于在当前状态下完成的工作结果)我还需要使用 if-else 吗?如果是这样,该模式的主要好处是什么?从我的角度来看,机器可能会从起始状态自动进行转换
在问之前,我已经阅读了以下内容,它只会加强我的观点:
在我的示例中,我有一个MarketPriceEvent需要存储在 Redis 中的对象。在存储之前,它必须通过验证路径。验证路径状态是:
问题是我要做出很多决定。例如:只有BasicValidation成功通过,我才想转移到Comparison. 现在,如果Comparison成功,我想移至Storing,否则移至ErrorAuditing。所以如果我们要进入代码:
_machine.Configure(State.Validate).PermitIf(Trigger.Validated, State.Compare1, () => isValid);
_machine.Configure(State.Compare1).OnEntry(CompareWithResource1).
PermitIf(Trigger.Compared, State.Store, () => isValid)
.PermitIf(Trigger.Compared, State.Compare2, () => !isValid);
Run Code Online (Sandbox Code Playgroud)
在我的客户端/包装器代码中,我会写:
//Stay at Validate state
var marketPriceProcessingMachine = new MarketPriceProcessingMachine();
if (marketPriceProcessingMachine.Permitted(Trigger.Validated))
marketPriceProcessingMachine.Fire(Trigger.Validated);
//else
// ...
Run Code Online (Sandbox Code Playgroud)
简而言之,如果我需要使用if-else,我从这样的状态机概念中得到了什么好处?如果它是确定性的,为什么它不会自我移动到下一个状态?如果我错了,怎么了?