我有一个涉及建模状态机的问题。
我已经设法做了一点知识工程和“逆向工程”一套原始的确定性规则来确定状态和状态转换。
我想知道最佳做法是什么:
如何严格测试我的状态和状态转换,以确保系统无法最终处于未确定状态。
如何强制执行状态转换要求(例如,应该不可能直接从stateFoo转到StateFooBar,即为每个状态灌输关于它可以转换到的状态的'知识'。
< / LI>理想情况下,我希望尽可能使用基于模式的干净设计,并使用模板。
我确实需要一个地方开始,我会感激任何指针(没有双关语意),这是我发送的。
答案 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搜索的其他一些好的参考资料
答案 4 :(得分:0)
听起来像单元测试的原始应用程序。那里有许多单元测试框架。我碰巧喜欢Boost one。
答案 5 :(得分:0)
如果您正在寻找经典的GOF设计模式状态机模式,请查看wikipedia。
在Java示例中查看此页面(在撰写本文时)。
它有一个StateContext
类,您可以从示例用法中看到,让客户知道writeName
方法。实现是:this.myState.writeName(this, name);
这意味着它将调用转发到当前状态,将自身作为第一个参数传递。
现在查看interface State
,它有一个writeName
方法,与上述用法相匹配。如果同时查看StateA
和StateB
,他们会回调上下文设置新状态。
那是大多数国家格局。唯一要认识到的是StateContext
类可以保存其操作中涉及的所有数据,包括对当前状态的引用(它必须是C ++中的指针)。所有州共同拥有所有行为,但没有数据,而是在上下文中推迟数据(加上辅助方法)。
当我正在开发状态机(我通常使用TDD)时,我不打扰测试状态转换,只是最终行为是我想要的。
答案 6 :(得分:0)
如果你喜欢状态设计模式我做了一个实验并将这个模式移到了库中: https://code.google.com/p/dpsmlib/