2012-11-12 33 views
8

bbv.Common.StateMachine class是我见过的最好的状态机器代码。但它缺乏一件事:获得现状。如何从bbv.Common.StateMachine(现在是Appccelerate.StateMachine)类获取当前状态?

这是一个订单跟踪系统:

fsm = new ActiveStateMachine<States, Events>(); 

     fsm.In(States.OrderCreated) 
      .On(Events.Submitted) 
      .Goto(States.WaitingForApproval); 
     fsm.In(States.WaitingForApproval) 
      .On(Events.Reject) 
      .Goto(States.Rejected); 
     fsm.In(States.WaitingForApproval) 
      .On(Events.Approve) 
      .Goto(States.BeingProcessed); 
     fsm.In(States.BeingProcessed) 
      .On(Events.ProcessFinished) 
      .Goto(States.SentByMail); 
     fsm.In(States.SentByMail) 
      .On(Events.Deliver) 
      .Goto(States.Delivered); 

     fsm.Initialize(States.OrderCreated); 
     fsm.Start(); 
     fsm.Fire(Events.Submitted); 
     // Save this state to database 

你可以看到它是如何工作的轻松。

但我想将订单状态保存在数据库中。因此,我将能够显示订单处于哪种状态。

我需要一个

fsm.GetCurrentState() 
//show this state in the a table 

方法。其实有一种方法:我可以使用ExecuteOnEntry并在每个州的条目上更改本地值。但为每个州写ExecuteOnEntry会很麻烦,因为我会重复自己!

必须有一个微妙的方式来做到这一点。

+1

难道你知道bbv.Common已被重命名为Appccelerate。看看我们的新主页http://www.appccelerate.com –

回答

13

正如丹尼尔解释说,这是由设计。让我解释一下为什么:

状态机允许排队事件。因此,向状态机询问其当前状态可能会产生误导。它目前处于状态A,但已经有一个事件排队等待状态B.

此外,我认为这是糟糕的设计,要将状态机内部状态(在您的状态机中使用的状态状态机定义)直接与状态机外部状态(你想要在数据库中保留的状态)相关联。如果直接将这两者耦合在一起,就会失去在内部重构状态机的能力,而不会影响外部(对于数据库)。我经常遇到这样的情景:我必须将状态A分解为A1和A2,因为我必须对它们附加不同的操作,但是它们仍然表示与环境相同的状态。 因此,我强烈建议您使用OnEntryExecute()编写或通过提供映射并使用扩展名来分隔内部和外部状态。这是一个扩展,将让你的当前状态:

public class CurrentStateExtension : ExtensionBase<State, Event> 
{ 
    public State CurrentState { get; private set; } 

    public override void SwitchedState(
     IStateMachineInformation<State, Event> stateMachine, 
     IState<State, Event> oldState, 
     IState<State, Event> newState) 
    { 
     this.CurrentState = newState.Id; 
    } 
} 

您可以通过这种方式添加扩展到状态机:

currentStateExtension = new CurrentStateExtension(); 
machine.AddExtension(currentStateExtension); 

当然,你可以直接使用该扩展来获得访问到现在的状态。 为了使它更简单,让定义状态机的类实现扩展并将其本身作为扩展传递。让你摆脱额外的课程。

最后要注意:当你在谷歌组在https://groups.google.com/forum/?fromgroups#!forum/appccelerate询问bbv.Common问题(或Appccelerate因为它现在叫),很容易让我找到了问题和回答这个问题;-)

+0

谢谢,我会尽快尝试。 –

4

这是设计。我们考虑查询状态机的状态作为设计气味。但当然也有例外情况。您有以下两种选择:

  1. 使用ExecuteOnEntry方法保存订单的状态。这反映了要走的路,因为你不想将状态机的状态泄漏到你的业​​务逻辑中。
  2. 写你自己的状态机装饰器,它在内部使用StateMachine<TState, TEvent>。这暴露了这个状态。

丹尼尔