2013-04-09 1 views
5

나는 간단한 동적 FSM을 썼다. DynamicConcreteStateB과 같이 상태 전환이 동적이지 정적 인 것을 의미합니다.동적 상태 머신을위한 .net 접근 더

namespace FSM_Example 
{ 
    using System; 

    class Program 
    { 
     static void Main() 
     { 
      var context = new Context(new ConcreteStateA()); 
      context.Run(); 
      Console.Read(); 
     } 
    } 

    abstract class State 
    { 
     public abstract void Execute(Context context); 
    } 

    class ConcreteStateA : State 
    { 
     public override void Execute(Context context) 
     { 
      context.State = new ConcreteStateB(); 
     } 
    } 

    class ConcreteStateB : State 
    { 
     public override void Execute(Context context) 
     { 
      Console.Write("Input state: "); 
      string input = Console.ReadLine(); 
      context.State = input == "e" ? null : new ConcreteStateA(); 
     } 
    } 

    class Context 
    { 
     private State _state; 

     public Context(State state) 
     { 
      State = state; 
     } 

     public State State 
     { 
      get { return _state; } 
      set 
      { 
       _state = value; 
       Console.WriteLine("State: " + _state.GetType().Name); 
      } 
     } 

     public void Run() 
     { 
      while (_state != null) 
      { 
       _state.Execute(this); 
      } 
     } 
    } 
} 

이것은 GoF305에 설명 된 상태 기계를 구현합니다.

저는 C#과 .net을 처음 사용 했으므로 .net 또는 C#의보다 구체적인 기능을 사용하여 더 나은 접근 방법이 있습니까?

답변

5

Outcoldman의 대답은 많은 훌륭한 옵션을 제공합니다 그것을 구현하는 것이

interface IState 
{ 
    Task HandleAsync(Context context); 
} 

class Context 
{ 
    // ... 

    public async Task RunAsync() 
    { 
     while (_state != null) 
     { 
      await _state.HandleAsync(this); 
     } 
    } 
} 
  • 나의 내기 같은 뭔가를 비동기를 사용할 수 있습니다.

    아래 코드는 패턴에 따라 적절한 FSM이 아니라는 것을 알고 있지만 매우 간단한 구현에서는 많은 추가 서브 클래스를 작성하는 것을 피할 수 있습니다. 작업에 적합한 도구를 결정하기 만하면됩니다. 이 사람은 주로 Action<T> 일반적인 위임의 사용을 주위에 초점을 맞추고 :

    public class Context 
    { 
        public Action<Context> State { get; internal set; } 
    
        public Context(Action<Context> state) 
        { 
         State = state; 
        } 
    
        public void Run() 
        { 
         while (State != null) 
         { 
          State(this); 
         } 
        } 
    } 
    

    과 같이 "상태 머신"이 :

    public static class SimpleStateMachine 
    { 
        public static void StateA(Context context) 
        { 
         context.State = StateB; 
        } 
        public static void StateB(Context context) 
        { 
         Console.Write("Input state: "); 
         var input = Console.ReadLine(); 
         context.State = input == "e" ? (Action<Context>)null : StateA; 
        } 
    } 
    

    프로세스를 발로 당신이 사용하는 것 :

    var context = new Context(SimpleStateMachine.StateA); 
    context.Run(); 
    Console.Read(); 
    

    또한 관련이없는 주에서는 다음과 같이 람다 식을 사용할 수도 있습니다.

    Action<Context> process = context => 
        { 
         //do something 
         context.State = nextContext => 
          { 
           //something else 
           nextContext.State = null; 
          }; 
        }; 
    
  • 2

    적용 할 수있는 방법이 많이 있지만 대부분 달성해야 할 작업에 따라 다릅니다.

    1. 추상 클래스 대신 인터페이스를 사용할 수 있습니다. C#에서는 두 개 이상의 클래스를 상속받을 수 없으므로 실현할 때이 옵션을 사용하지 않는 것이 좋습니다.

      interface IState 
      { 
          void Handle(Context context); 
      } 
      
    2. 번 주 패턴에 대한 기본 인터페이스/클래스를 작성하고 모든 곳에서 사용할 수 있도록 당신은 제네릭을 사용할 수 있습니다

      abstract class IState<T> 
      { 
          void Handle(T context); 
      } 
      
    3. 다음 일을 숨기거나 돈을 원하는가에 따라 달라 숨기고 싶지 않아. 예를 들어 아무도 dll 외부에서 사용할 수 없도록 보장하기 위해 속성 State에 대한 setter를 숨길 수 있으므로이 속성의 설정자는 internal이 될 수 있습니다.

    4. 당신은 상태 변경, 누군가가 이미 Rx