使用有限状态机控制其包含对象的OO方法是什么



我目前正在基于这个例子将游戏中的人工智能重构为有限状态机,我选择这个例子是因为它的可读性和高度可视化的定义格式:

class FiniteStateMachine
{
    public enum States { Start, Standby, On };
    public States State { get; set; }
    public enum Events { PlugIn, TurnOn, TurnOff, RemovePower };
    private Action[,] fsm;
    public FiniteStateMachine()
    {
        this.fsm = new Action[3, 4] { 
        PlugIn,       TurnOn,                 TurnOff,            RemovePower
        {this.PowerOn,  null,                   null,               null},              //start
        {null,          this.StandbyWhenOff,    null,               this.PowerOff},     //standby
        {null,          null,                   this.StandbyWhenOn, this.PowerOff} };   //on
    }
    public void ProcessEvent(Events theEvent)
    {
        this.fsm[(int)this.State, (int)theEvent].Invoke();
    }
    private void PowerOn() { this.State = States.Standby; }
    private void PowerOff() { this.State = States.Start; }
    private void StandbyWhenOn() { this.State = States.Standby; }
    private void StandbyWhenOff() { this.State = States.On; }
}

这个状态机类是由父对象实例化的,为了匹配这个简单的例子,我将其称为"Device"。

我现在想弄清楚的是,如何最好地扩展它来实现各种状态和过渡行为。想象一下,Device类有一个计数器,每当我们打开电源时,我们都想增加它。我们如何增加这个计数器?

这里用于转换行为的Action委托不接受FiniteStateMachine类之外的参数,我敢肯定,无论如何,从这里对包含类进行更改都是非常糟糕的做法。

但是,如果我不打算实现这个类中的任何实际行为,我觉得我一开始就错过了实现有限状态机的要点。当我试图执行非法状态更改时,我理解它抛出空引用异常的好处,但计划是让它也包含行为。

如果没有,那么我实际上并没有更改任何现有的行为代码:我只是重构它以调用ProcessEvent(),而不是直接从调用代码中设置State。更安全,但不干净。

所以我的问题是:
1.实现影响其包含类的有限状态机的行为元素的最干净的方法是什么
2.为了实现这一点,我是否应该放弃上述FSM模型,而选择不同的FSM模型?

您应该检查状态模式(如zerkms注释中所建议的)。

这将允许您轻松地对状态转换执行其他操作。

在使用状态模式时,您仍然需要决定如何允许各个状态共享数据。如果将共享数据放在上下文类中,那么很难在不公开的情况下将其公开给状态。C++实现通常使用friend来允许状态访问上下文中的私有数据。在C#中,我有时会将共享数据封装在一个单独的类中,该类从上下文传递到状态,但不会由上下文或状态公开。

如果你在摸索了状态模式后还不清楚,那么添加一条注释,我就可以发布一些代码了。

最新更新