【问题标题】:Designing a state machine in C++用 C++ 设计状态机
【发布时间】:2010-04-24 16:15:02
【问题描述】:
我有一个涉及到状态机建模的小问题。
我已经设法进行了一些知识工程并“逆向工程”了一组确定状态和状态转换的原始确定性规则。
我想知道最佳做法是什么:
理想情况下,我希望尽可能使用干净、基于模式的设计,并使用模板。
不过,我确实需要从某个地方开始,我将不胜感激任何以我的方式发送的指示(不是双关语)。
【问题讨论】:
标签:
c++
design-patterns
state-machine
state-pattern
【解决方案2】:
天哪,它并不像看起来那么复杂。状态机代码非常简单简短。
将状态存储在一个变量中,比如 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% 单元测试通过并没有多大意义。
换句话说:编写状态机很容易,设计正确的状态机很难。单元测试只会告诉你设计是否正确,而不是设计是否正确。
【解决方案3】:
测试与模式、模板等几乎没有关系。我建议使用像 CppUnit(xUnit 系列的一部分)这样的测试框架来捕获所有测试用例。当然,数量取决于状态机的复杂程度。
您关于强制状态转换的问题涉及到您的状态机类设计的核心。我想说一个状态将有一组可以转换到的子状态,以及触发每个状态的事件。如果事件 Foo 没有 FooBar 子级,则无法转换到它。
我会在 Google 上搜索“面向对象的有限状态机”来开始获得一些设计理念。
当我考虑这样的问题时,我认为复合设计模式可能是其中的一部分,因为状态可能代表更复杂的 FSM。我会有一个 State 接口,使用 SimpleState 和 CompositeState 作为实现。我得重新开始,看看能不能解决。
【解决方案5】:
听起来像是一个用于单元测试的原始应用程序。有许多单元测试框架。我碰巧喜欢Boost one。
【解决方案6】:
如果您正在寻找经典的 GOF 设计模式状态机模式,请查看wikipedia。
查看此页面(在撰写本文时)的 Java 示例。
它有一个StateContext 类,您可以从示例用法中看到,它的客户端知道writeName 方法。实现是:this.myState.writeName(this, name);,这意味着它将调用转发到当前状态,并将自身作为第一个参数传递。
现在看看interface State,它有一个writeName 方法与上述用法相匹配。如果您同时查看StateA 和StateB,它们会回调上下文设置新状态。
这就是大部分的状态模式。唯一需要意识到的是,StateContext 类可以保存其操作中涉及的所有数据,包括对当前状态的引用(它必须是 C++ 中的指针)。所有状态共同保存所有行为,但没有数据,而是在上下文中延迟数据(加上辅助方法)。
当我开发状态机时(我通常使用 TDD),我不会费心测试状态转换,只是最终的行为是我想要的。