更多的.net方法用于动态状态机
本文关键字:用于 动态 状态机 方法 net | 更新日期: 2023-09-27 18:08:15
我写了一个简单的动态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的新手:是否有更好的方法使用.net
或C#
的更具体的功能来实现这个目标?
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;
};
};
您可以使用很多方法,但主要取决于您需要完成的任务。
-
可以用接口代替抽象类。在c#中,你不能继承一个以上的类,所以最好不要从实现中选择这个选项。
interface IState { void Handle(Context context); }
-
你可以使用泛型,所以你可以为状态模式编写一次基接口/类,然后在任何地方使用它:
abstract class IState<T> { void Handle(T context); }
-
接下来的事情取决于你想隐藏或不想隐藏什么。例如,你可以隐藏属性State的setter,以确保没有人可以在你的dll之外使用,所以你可以将这个属性的setter设置为
internal
。 -
你可以使用Async来改变状态,比如
interface IState { Task HandleAsync(Context context); } class Context { // ... public async Task RunAsync() { while (_state != null) { await _state.HandleAsync(this); } } }
-
我打赌有人已经用Rx实现了它