用C ++设计状态机

时间:2010-04-24 16:15:03

标签: c++ design-patterns state state-machine

我有一个涉及建模状态机的问题。

我已经设法做了一点知识工程和“逆向工程”一套原始的确定性规则来确定状态和状态转换。

我想知道最佳做法是什么:

  • 如何严格测试我的状态和状态转换,以确保系统无法最终处于未确定状态。

  • 如何强制执行状态转换要求(例如,应该不可能直接从stateFoo转到StateFooBar,即为每个状态灌输关于它可以转换到的状态的'知识'。

    < / LI>

理想情况下,我希望尽可能使用基于模式的干净设计,并使用模板。

我确实需要一个地方开始,我会感激任何指针(没有双关语意),这是我发送的。

7 个答案:

答案 0 :(得分:7)

请务必查看Boost Statechart Library

答案 1 :(得分:3)

天哪,它并不像看起来那么复杂。状态机代码非常简单和简短。

将状态存储在变量中,假设是myState。

你的状态机将是一个switch语句,分支myState变量的值来运行每个状态的代码。

代码将充满这样的行:

myState = newState;

要强制执行状态转换要求,您需要添加一个名为的方法,例如

void DoSafeStateTransition( int newState )
{
// check myState -. newState is not forbidden
// lots of ways to do this
// perhaps nested switch statement

switch( myState ) {

 …

case X:  switch( newState ) 
    case A: case B:  case Z: HorribleError( newState );
    break;

 ...

}

// check that newState is not undetermined

switch( newState ) {

// all the determined states
case A: case B: case C … case Z: myState = newState; break;
default: HorribleError( newState );
}
}
void HorribleError( int newState )
{  printf("Attempt to go from %d to %d - disallowed\n",
       myState, newState );
   exit(1);
}

我建议这个简单而且足够短,检查将比单元测试做得更好 - 它肯定会快得多!

在我看来,单元测试的重点是测试代码比测试的代码更简单,因此可以更容易地检查它的正确性,然后用于测试复杂的代码。检查状态机代码通常比状态机测试代码更容易。当您不知道单元测试是否正确时,报告100%单元测试通过没有多大意义。

换句话说:编写状态机很容易,设计正确的很难。单元测试只会告诉您是否正确编码了设计,而不是设计是否正确。

答案 2 :(得分:1)

测试与模式,模板等几乎没有关系。我建议使用像CppUnit(xUnit系列的一部分)这样的测试框架来捕获所有测试用例。当然,这个数字取决于状态机的复杂程度。

关于强制执行状态转换的问题是您的状态机的类设计的核心。我会说一个州将拥有一个可以转换到的子州的集合,以及将触发每个州的事件。如果事件Foo没有FooBar子项,那么就无法转换到它。

我使用谷歌“面向对象的有限状态机”来开始获得一些设计思路。

当我考虑这样的问题时,我认为复合设计模式可能是其中的一部分,因为状态可能代表更复杂的FSM。我有一个State接口,SimpleState和CompositeState作为实现。我必须重新开始,看看它是否能全部解决。

答案 3 :(得分:1)

使用状态机是不时出现的问题。我通常做ravenspoint建议并简单地做一个switch语句。但是,这只有在州不太大的情况下才有效。这听起来像你的情况。考虑到这一点,我认为最好的方法是从一个良好的架构开始,这将允许您想要做的一些事情。我拿了duffymo的建议并尝试了谷歌。这篇论文看起来很有意思 - Object-Oriented State Machines。它可能有点矫枉过正,但我​​认为这将提供一个易于使用CppUnit等测试的框架。

Google搜索的其他一些好的参考资料

A Finite State Machine Framework

Object-Oriented Finite State Machines

答案 4 :(得分:0)

听起来像单元测试的原始应用程序。那里有许多单元测试框架。我碰巧喜欢Boost one

答案 5 :(得分:0)

如果您正在寻找经典的GOF设计模式状态机模式,请查看wikipedia

在Java示例中查看此页面(在撰写本文时)。

它有一个StateContext类,您可以从示例用法中看到,让客户知道writeName方法。实现是:this.myState.writeName(this, name);这意味着它将调用转发到当前状态,将自身作为第一个参数传递。

现在查看interface State,它有一个writeName方法,与上述用法相匹配。如果同时查看StateAStateB,他们会回调上下文设置新状态。

那是大多数国家格局。唯一要认识到的是StateContext类可以保存其操作中涉及的所有数据,包括对当前状态的引用(它必须是C ++中的指针)。所有州共同拥有所有行为,但没有数据,而是在上下文中推迟数据(加上辅助方法)。

当我正在开发状态机(我通常使用TDD)时,我不打扰测试状态转换,只是最终行为是我想要的。

答案 6 :(得分:0)

如果你喜欢状态设计模式我做了一个实验并将这个模式移到了库中: https://code.google.com/p/dpsmlib/