switch (state) {
// 处理状态Opened的分支
case (Opened): {
// 执行动作Open
open();
// 检查是否有CloseDoor事件
if (closeDoor()) {
// 当前状态转换为Closed
changeState(Closed)
}
break;
}
// 处理状态Closed的分支
case (Closed): {
// 执行动作Close
close();
// 检查是否有OpenDoor事件
if (openDoor()) {
// 当前状态转换为Opened
changeState(Opened);
}
// 检查是否有LockDoor事件
if (lockDoor()) {
// 当前状态转换为Locked
changeState(Locked);
}
break;
}
// 处理状态Locked的分支
case (Locked): {
// 执行动作Lock
lock();
// 检查是否有UnlockDoor事件
if (unlockDoor()) {
// 当前状态转换为Unlocked
changeState(Unlocked);
}
break;
}
// 处理状态Unlocked的分支
case (Unlocked): {
// 执行动作Unlock
unlock();
// 检查是否有LockDoor事件
if (lockDoor()) {
// 当前状态转换为Locked
changeState(Locked)
}
// 检查是否有OpenDoor事件
if (openDoor()) {
// 当前状态转换为Opened
changeSate(Opened);
}
break;
}
}
使用switch语句实现的有限状态机的确能够很好地工作,但代码的可读性并不十分理想,主要原因是在实现状态之间的转换时,检查转换条件和进行状态转换都是混杂在当前状态中来完成的。例如,当城门处于Opened状态时,需要在相应的case中调用closeDoor()函数来检查是否有必要进行状态转换,如果是的话则还需要调用changeState()函数将当前状态切换到Closed。显然,如果在每种状态下都需要分别检查多个不同的转换条件,并且需要根据检查结果让状态机切换到不同的状态,那么这样的代码将是枯燥而难懂的。从代码重构的角度来讲,此时更好的做法是引入checkStateChange()和performStateChange()两个函数,专门用来对转换条件进行检查,以及激活转换时所需要执行的各种动作。这样一来,程序结构将变得更加清晰:
switch (state) {
// 处理状态Opened的分支
case (Opened): {
// 执行动作Open
open();
// 检查是否有激发状态转换的事件产生
if (checkStateChange()) {
// 对状态机的状态进行转换
performStateChange();
}
break;
}
// 处理状态Closed的分支
case (Closed): {
// 执行动作Close
close();
// 检查是否有激发状态转换的事件产生
if (checkStateChange()) {
// 对状态机的状态进行转换
performStateChange();
}
break;
}
// 处理状态Locked的分支
case (Locked): {
// 执行动作Lock
lock();
// 检查是否有激发状态转换的事件产生
if (checkStateChange()) {
// 对状态机的状态进行转换
performStateChange();
}
break;
}
// 处理状态Unlocked的分支
case (Unlocked): {
// 执行动作Lock
unlock();
// 检查是否有激发状态转换的事件产生
if (checkStateChange()) {
// 对状态机的状态进行转换
performStateChange();
}
break;
}
}
但checkStateChange()和performStateChange()这两个函数本身依然会在面对很复杂的状态机时,内部逻辑变得异常臃肿,甚至可能是难以实现。在很长一段时期内,使用switch语句一直是实现有限状态机的唯一方法,甚至像编译器这样复杂的软件系统,大部分也都直接采用这种实现方式。但之后随着状态机应用的逐渐深入,构造出来的状态机越来越复杂,这种方法也开始面临各种严峻的考验,其中最令人头痛的是如果状态机中的状态非常多,或者状态之间的转换关系异常复杂,那么简单地使用switch语句构造出来的状态机将是不可维护的。
[xiaowp@linuxgam code]$ fsmc door.fsm -d -o DoorFSM.h
进一步还可以生成包含有状态机实现的框架代码:
[xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp
如果想对生成的状态机进行验证,只需要再手工编写一段用于测试的代码就可以了:
/*
* TestFSM.cpp
* 测试生成的状态机框架
*/
int main()
{
DoorFSM door;
door.A(DoorFSM::Close);
door.A(DoorFSM::Lock);
door.A(DoorFSM::Unlock);
door.A(DoorFSM::Open);
}
有限状态机是由事件来进行驱动的,在FSME生成的状态机框架代码中,方法A()可以被用来向状态机发送相应的事件,从而提供状态机正常运转所需要的"动力"。状态机负责在其内部维护一个事件队列,所有到达的事件都会先被放到事件队列中进行等候,从而能够保证它们将按照到达的先后顺序被依次处理。在处理每一个到达的事件时,状态机都会根据自己当前所处的状态,检查与该状态对应的转换条件是否已经被满足,如果满足的话则激活相应的状态转换过程。使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:
[xiaowp@linuxgam code]$ g++ DoorFSM.cpp TestFSM.cpp -o fsm
由于之前在用fsmc命令生成状态机代码时使用了-d选项,生成的状态机框架中会包含一定的调试信息,包括状态机中每次状态转换时的激活事件、转换前的状态、所经历的转换、转换后的状态等,如下所示:
[
]$ ./fsmDoorFSM:event:'Close'
DoorFSM'Opened'
DoorFSM'closeDoor'
DoorFSM:new state:'Closed'
DoorFSM:event:'Lock'
DoorFSM'Closed'
DoorFSM'lockDoor'
DoorFSM:new state:'Locked'
DoorFSM:event:'Unlock'
DoorFSM'Locked'
DoorFSM'unlockDoor'
DoorFSM:new state:'Unlocked'
DoorFSM:event:'Open'
DoorFSM'Unlocked'
DoorFSM'openDoor'
DoorFSM:new state:'Opened'
[xiaowp@linuxgam code]$ fsmc door.fsm -o DoorFSM.h
[xiaowp@linuxgam code]$ fsmc door.fsm -d -impl DoorFSM.h -o DoorFSM.cpp
我们在新的状态机模型中添加了enterOpend、enterClosed、enterLocked和enterUnlocked四个输出,因此生成的类DoorFSM中会包含如下几个纯虚函数:
virtual void enterOpened() = 0;
virtual void enterLocked() = 0;
virtual void enterUnlocked() = 0;
virtual void enterClosed() = 0;
显然,此时生成的状态机框架不能够再被直接编译了,我们必须从类DoorFSM派生出一个子类,并提供对这几个纯虚函数的具体实现:
/*
* DoorFSMLogic.h
* 状态机控制逻辑的头文件
*/
class DoorFSMLogic : public DoorFSM
{
protected:
virtual void enterOpened();
virtual void enterLocked();
virtual void enterUnlocked();
virtual void enterClosed();
};
正如前面所提到过的,这几个函数实际上代表的正是应用系统的处理逻辑,作为例子我们只是简单地输出一些提示信息:
/*
* DoorFSMLogic.cpp
* 状态机控制逻辑的实现文件
*/
void DoorFSMLogic::enterOpened()
{
std::cout << "Enter Opened state." << std::endl;
}
void DoorFSMLogic::enterClosed()
{
std::cout << "Enter Closed state." << std::endl;
}
void DoorFSMLogic::enterLocked()
{
std::cout << "Enter Locked state." << std::endl;
}
void DoorFSMLogic::enterUnlocked()
{
std::cout << "Enter Unlocked state." << std::endl;
}
同样,为了对生成的状态机进行验证,我们还需要手工编写一段测试代码:
/*
* TestFSM.cpp
* 测试状态机逻辑
*/
int main()
{
DoorFSMLogic door;
door.A(DoorFSM::Close);
door.A(DoorFSM::Lock);
door.A(DoorFSM::Unlock);
door.A(DoorFSM::Open);
}
使用下面的命令能够将生成的状态机框架和测试代码编译成一个可执行文件:
[xiaowp@linuxgam code]$ g++ DoorFSM.cpp DoorFSMLogic.cpp TestLogic.cpp -o logic
运行结果如下所示:
code]$ ./logic
Enter Closed state.
Enter Locked state.
Enter Unlocked state.
Enter Opened state.
本文涉及代码下载: http://www.uml.org.cn/umlcode/code.zip全部0条评论
快来发表一下你的评论吧 !