2016-02-04 4 views
1

Недавно я использовал конечный автомат Stateless. Я могу определить правила для переходов и т.д., как это:Statemachine, которая переходит в целевое состояние и запускает переходы и состояния между ними?

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); 

, а затем вы можете стрелять триггер, чтобы изменить состояние. Однако вам нужно знать текущее состояние и что будет следующим состоянием, если вы хотите перейти в конкретное состояние. Таким образом, «клиент» statemachine нуждается в знаниях, как достичь определенного состояния, если нет прямого перехода. Есть ли возможность называть что-то вроде «goto», и машина запускает все необходимые триггеры?

ответ

1

Вы можете сделать это, существует только ОДНО «Разрешение» на каждое государство. Если у вас есть несколько «Разрешений», вы не можете автоматически перемещать рабочий процесс (должна быть какая-то причина, по которой вы выбрали бы один разрешающий/триггер над другим). Когда я говорю, что вы «не можете», это не технически, его практически.

Ниже приведен пример автоматического перемещения по рабочему процессу.

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 
} 

и теперь трюк с автоматическим перемещением.

  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 и получить первый-один (и авто-ход, чтобы работать там должен быть только один Разрешенное-триггера каждого государства) ..... а затем вызвать этот триггер.

Опять же, практически (не технически) вы сделали бы это только в том случае, если было одно разрешение/триггер на каждое государство. Таким образом, почему у меня есть исключение, если есть больше 1. Вы можете «получить первое», если их было больше 1, это просто не имело бы смысла.

 Смежные вопросы

  • Нет связанных вопросов^_^