7

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

我已经设法进行了一些知识工程并“逆向工程”了一组确定状态和状态转换的原始确定性规则。

我想知道最佳实践是什么:

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

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

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

不过,我确实需要从某个地方开始,我将不胜感激任何以我的方式发送的指示(不是双关语)。

4

7 回答 7

7

请务必查看Boost Statechart Library

于 2010-04-24T16:54:34.717 回答
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% 单元测试通过并没有多大意义。

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

于 2010-04-24T16:48:21.183 回答
1

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

您关于强制状态转换的问题涉及到您的状态机类设计的核心。我想说一个状态将有一组可以转换到的子状态,以及触发每个状态的事件。如果事件 Foo 没有 FooBar 子级,则无法过渡到它。

我会谷歌“面向对象的有限状态机”来开始获得一些设计理念。

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

于 2010-04-24T16:19:43.913 回答
1

使用状态机是不时出现的。我通常按​​照 ravenspoint 的建议做,然后简单地做一个 switch 语句。但是,这只有在州不太大的情况下才有效。这听起来像你的情况。考虑到这一点,我认为最好的办法是从一个好的架构开始,它允许你做一些你想做的事情。我接受了 duffymo 的建议并尝试了谷歌。这篇论文看起来很有趣——面向对象的状态机。这可能有点矫枉过正,但我​​认为它会提供一个易于使用 CppUnit 之类的东西进行测试的框架。

谷歌搜索中的其他一些很好的参考资料

有限状态机框架

面向对象的有限状态机

于 2010-04-24T17:32:37.757 回答
0

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

于 2010-04-24T16:18:23.760 回答
0

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

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

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

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

这就是大部分的状态模式。唯一需要意识到的是,StateContext该类可以保存其操作所涉及的所有数据,包括对当前状态的引用(它必须是 C++ 中的指针)。所有状态共同持有所有行为,但没有数据,而是在上下文中延迟数据(加上辅助方法)。

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

于 2010-04-24T22:46:02.310 回答
0

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

于 2013-11-28T19:57:17.797 回答