更多.net方法用于动态状态机

时间:2013-04-09 21:38:53

标签: c# .net winforms design-patterns state-machine

我写了一个简单的动态FSM。 Dynamic表示状态转换是动态的,而不是静态的,如ConcreteStateB所示。

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的新手:是否有更好的方法可以使用.netC#中更具体的功能来实现这一目标?

2 个答案:

答案 0 :(得分:5)

Outcoldman的回答提供了许多很好的选择。

现在,根据模式,我知道下面的代码不是一个合适的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();

此外,对于不相关的状态,您也可以使用Lambda表达式,例如:

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

答案 1 :(得分:2)

您可以应用很多方法,但主要取决于您需要实现的任务。

  1. 您可以使用interface而不是abstract class。在C#中,你不能继承多个类,所以不要从实现中获取这个选项总是好的。

    interface IState
    {
         void Handle(Context context);
    }
    
  2. 您可以使用泛型,因此您可以为State模式编写一次基本接口/类,并在任何地方使用它:

    abstract class IState<T>
    {
         void Handle(T context);
    }
    
  3. 接下来的事情取决于你想要隐藏或不想隐藏的内容。例如,您可以隐藏属性State的setter,以确保没有人可以在您的dll之外使用,因此您可以创建此属性internal的setter。

  4. 您可以使用Async进行状态更改,例如

    interface IState
    {
         Task HandleAsync(Context context);
    }
    
    class Context
    {
        // ...
    
        public async Task RunAsync()
        {
            while (_state != null)
            {
                await _state.HandleAsync(this);
            }
        }
    }
    
  5. 我敢打赌有人已经用Rx

  6. 实现了它