2013-04-09 4 views
5

Ich schrieb eine einfache dynamische FSM. bedeutet, dass die Zustandsübergänge dynamisch und nicht statisch sind, wie in ConcreteStateB gezeigt.Mehr .net-Ansatz für dynamische Zustandsmaschine

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

Dies implementiert eine Zustandsmaschine wie in GoF305 beschrieben.

Da ich neu in C# und .net bin: Gibt es bessere Ansätze, die dieses Ziel mit spezifischeren Funktionen von .net oder C# erreichen?

Antwort

5

Outcoldman Antwort zahlreiche große Möglichkeiten bietet.

Nun, ich weiß, dass der unten stehende Code keine ordnungsgemäße FSM nach dem Muster ist, aber für sehr einfache Implementierungen könnte es Ihnen helfen, zu vermeiden, viele zusätzliche Unterklassen zu schreiben. Es ist nur eine Frage der Entscheidung für das richtige Werkzeug für den Job. Dieser konzentriert sich in erster Linie um die Verwendung der Action<T> generic Delegierten:

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

Und haben die „Zustandsmaschine“, wie:

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

Und für den Prozess Auftakt würden Sie verwenden:

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

Auch für Staaten, die nicht verwandt sind, können Sie auch Lambda-Ausdrücke verwenden, wie zum Beispiel:

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

Es gibt viele Ansätze, die Sie anwenden können, aber meistens hängt es von der Aufgabe ab, die Sie erreichen müssen.

  1. Sie können Schnittstelle anstelle der abstrakten Klasse verwenden. In C# können Sie nicht mehr als eine Klasse erben, daher ist es immer gut, diese Option nicht zu realisieren.

    interface IState 
    { 
        void Handle(Context context); 
    } 
    
  2. Sie können Generika verwenden, so dass Sie die Basis schreiben können Schnittstellen/Klassen für staatliche Muster einmal und es überall verwenden:

    abstract class IState<T> 
    { 
        void Handle(T context); 
    } 
    
  3. Nächste Dinge davon abhängen, was wollen Sie verstecken oder don Ich möchte mich nicht verstecken. Zum Beispiel können Sie wahrscheinlich Setter für Eigenschaft State ausblenden, um sicherzustellen, dass niemand außerhalb Ihrer DLL verwenden kann, so dass Sie den Setter dieser Eigenschaft internal machen können.

  4. können Sie Async verwenden für State Change, so etwas wie

    interface IState 
    { 
        Task HandleAsync(Context context); 
    } 
    
    class Context 
    { 
        // ... 
    
        public async Task RunAsync() 
        { 
         while (_state != null) 
         { 
          await _state.HandleAsync(this); 
         } 
        } 
    } 
    
  5. Meine Wette, dass jemand bereits mit Rx umgesetzt

Verwandte Themen