层次状态机(Hierarchical State Machine, HSM),从基本原理、结构设计、实现方法以及如何结合 Qt 进行具体实现等方面进行分析。
1. 层次状态机的基本原理
层次状态机是一种用于管理复杂系统行为的状态机模型,它通过将状态组织成层次结构来简化设计和维护。这种结构使得复杂的逻辑可以分解为更小、更易于管理的部分。
关键概念:
- 状态(State): 系统在某一时刻所处的条件或模式。
- 事件(Event): 触发状态转换的信息或信号。
- 转换(Transition): 从一个状态到另一个状态的迁移过程。
- 动作(Action): 在进入、离开状态或进行转换时执行的操作。
- 父状态和子状态:
- 父状态(Superstate): 包含多个子状态的状态。
- 子状态(Substate): 属于某个父状态的更具体的状态。
特点:
- 嵌套结构: 状态可以嵌套在其他状态中,形成层次结构。
- 继承行为: 子状态可以继承父状态的行为和动作。
- 事件委托: 事件可以从子状态传递到父状态进行处理。
- 简化设计: 将复杂的状态逻辑分解为更小的、可管理的部分。
2. 层次状态机的设计
在设计层次状态机时,需要仔细规划状态之间的关系以及如何组织这些状态。以下是一些设计原则和步骤:
设计步骤:
-
识别顶级状态:
- 确定系统的基本操作模式或主要功能。
- 例如,在一个电梯系统中,顶级状态可能包括“待命”、“运行”和“维护”。
-
定义子状态:
- 对于每个顶级状态,进一步分解为更具体的状态。
- 例如,“运行”状态可以包含“上升”、“下降”和“停止”等子状态。
-
确定事件和转换:
- 定义可能触发状态转换的事件。
- 确定每个状态在接收到特定事件时应执行的操作以及如何进行转换。
- 例如,“上升”状态在接收到“到达楼层”事件时,可以转换到“停止”状态。
-
实现继承和委托:
- 设计父状态的行为,并让子状态继承这些行为。
- 当子状态无法处理某个事件时,将该事件传递给其父状态进行处理。
-
编写动作函数:
- 实现每个状态的进入(Entry)、离开(Exit)操作以及转换期间的动作(Action)。
- 例如,在“上升”状态下进入时启动电机,在离开时停止电机。
-
定义初始状态和历史状态:
- 指定每个复合状态的初始子状态。
- 使用历史状态来记住上次活动的子状态,以便在返回该状态时恢复到之前的状态。
示例:
假设我们设计一个简单的电视遥控器状态机,包含以下状态:
- 待命(Standby)
- 运行(Running)
- 频道选择(Channel Selection)
- 浏览模式(Browse Mode)
- 锁定模式(Lock Mode)
- 音量控制(Volume Control)
- 频道选择(Channel Selection)
事件包括:
POWER
CHANNEL_UP
,CHANNEL_DOWN
VOLUME_UP
,VOLUME_DOWN
MODE_SWITCH
状态图示例:
+-------------------+| Standby |+--------+----------+|POWER|+----v-----+| Running |+--+-+------+| |CHANNEL_UP|VOLUME_DOWN/ | \/ v \+------------+ +------------+| Browse Mode| |Volume Ctrl|+------------+ +------------+
3. 层次状态机的实现
在实际编程中,层次状态机可以通过多种方式实现。以下是一个使用 C++ 和 Qt 的具体示例。
使用结构体定义状态和事件
首先,我们定义状态、事件及其处理函数的类型:
#include <QObject>
#include <QVector>
#include <QDebug>namespace HSMUtilityDef {typedef uint32_t HSM_EVENT;// 定义常见事件const uint32_t MAX_DEPTH = 5;const HSM_EVENT HSME_NULL = 0;const HSM_EVENT HSME_START = 1;const HSM_EVENT HSME_INIT = static_cast<HSM_EVENT>(-3);const HSM_EVENT HSME_ENTRY = static_cast<HSM_EVENT>(-2);const HSM_EVENT HSME_EXIT = static_cast<HSM_EVENT>(-1);// 自定义事件const HSM_EVENT POWER = 100;const HSM_EVENT CHANNEL_UP = 101;const HSM_EVENT CHANNEL_DOWN = 102;const HSM_EVENT VOLUME_UP = 103;const HSM_EVENT VOLUME_DOWN = 104;const HSM_EVENT MODE_SWITCH = 105;
}
定义状态基类
创建一个抽象基类 HSMState
,包含处理事件的虚函数:
class HSMState : public QObject {Q_OBJECTpublic:explicit HSMState(HSMState *parent = nullptr) : QObject(parent), m_parent(parent) {}virtual ~HSMState() {}// 处理事件的主要接口virtual HSMUtilityDef::HSM_EVENT handleEvent(HSMUtilityDef::HSM_EVENT event, void* param = nullptr) {switch (event) {case HSMUtilityDef::HSME_ENTRY:onEntry(param);break;case HSMUtilityDef::HSME_EXIT:onExit(param);break;default:return unhandledEvent(event, param);}return HSMUtilityDef::HSME_NULL;}protected:// 进入状态时执行的动作virtual void onEntry(void* param) {}// 离开状态时执行的动作virtual void onExit(void* param) {}// 处理未定义事件的方法virtual HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) {qDebug() << "Unhandled event" << event;return event;}// 获取父状态HSMState* parent() const { return m_parent; }private:HSMState *m_parent;
};
定义具体状态类
创建具体的派生状态类,实现特定的逻辑:
// 待命状态(Standby)
class StandbyState : public HSMState {Q_OBJECTpublic:explicit StandbyState(HSMState* parent = nullptr) : HSMState(parent) {}protected:void onEntry(void* param) override {qDebug() << "Entering Standby State";}void onExit(void* param) override {qDebug() << "Exiting Standby State";}HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) override {if (event == HSMUtilityDef::POWER) {return static_cast<HSMUtilityDef::HSM_EVENT>(HSMUtilityDef::HSME_INIT);}return HSMState::unhandledEvent(event, param);}
};// 运行状态(Running)
class RunningState : public HSMState {Q_OBJECTpublic:explicit RunningState(HSMState* parent = nullptr) : HSMState(parent) {}protected:void onEntry(void* param) override {qDebug() << "Entering Running State";}void onExit(void* param) override {qDebug() << "Exiting Running State";}HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) override {if (event == HSMUtilityDef::POWER) {return static_cast<HSMUtilityDef::HSM_EVENT>(HSMUtilityDef::HSME_EXIT);}return HSMState::unhandledEvent(event, param);}
};// 频道选择状态(Channel Selection)
class ChannelSelectionState : public HSMState {Q_OBJECTpublic:explicit ChannelSelectionState(HSMState* parent = nullptr) : HSMState(parent), m_currentMode(BROWSE_MODE) {}protected:void onEntry(void* param) override {qDebug() << "Entering Channel Selection State";}void onExit(void* param) override {qDebug() << "Exiting Channel Selection State";}HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) override {switch (event) {case HSMUtilityDef::CHANNEL_UP:channelUp();break;case HSMUtilityDef::CHANNEL_DOWN:channelDown();break;case HSMUtilityDef::MODE_SWITCH:modeSwitch();break;default:return HSMState::unhandledEvent(event, param);}return HSMUtilityDef::HSME_NULL;}private:enum Mode {BROWSE_MODE,LOCK_MODE};Mode m_currentMode;void channelUp() {if (m_currentMode == BROWSE_MODE) {qDebug() << "Channel Up in Browse Mode";} else if (m_currentMode == LOCK_MODE) {qDebug() << "Channel Up in Lock Mode";}}void channelDown() {if (m_currentMode == BROWSE_MODE) {qDebug() << "Channel Down in Browse Mode";} else if (m_currentMode == LOCK_MODE) {qDebug() << "Channel Down in Lock Mode";}}void modeSwitch() {if (m_currentMode == BROWSE_MODE) {m_currentMode = LOCK_MODE;qDebug() << "Switched to Lock Mode";} else {m_currentMode = BROWSE_MODE;qDebug() << "Switched to Browse Mode";}}
};// 音量控制状态(Volume Control)
class VolumeControlState : public HSMState {Q_OBJECTpublic:explicit VolumeControlState(HSMState* parent = nullptr) : HSMState(parent) {}protected:void onEntry(void* param) override {qDebug() << "Entering Volume Control State";}void onExit(void* param) override {qDebug() << "Exiting Volume Control State";}HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) override {switch (event) {case HSMUtilityDef::VOLUME_UP:volumeUp();break;case HSMUtilityDef::VOLUME_DOWN:volumeDown();break;default:return HSMState::unhandledEvent(event, param);}return HSMUtilityDef::HSME_NULL;}private:void volumeUp() {qDebug() << "Volume Up";}void volumeDown() {qDebug() << "Volume Down";}
};
定义层次状态机类
创建一个管理状态转换的主类 HSM
:
class HSM : public QObject {Q_OBJECTpublic:explicit HSM(QObject* parent = nullptr) : QObject(parent), m_currentState(nullptr) {}void start(HSMState* initialState) {if (m_currentState == nullptr) {initialize(initialState);}}void processEvent(HSMUtilityDef::HSM_EVENT event, void* param = nullptr) {if (m_currentState != nullptr) {HSMState* nextState = m_currentState;HSMUtilityDef::HSM_EVENT nextEvent = event;// 处理事件,直到返回 HSME_NULLwhile (nextEvent != HSMUtilityDef::HSME_NULL) {nextState = processSingleEvent(nextState, nextEvent, param);nextEvent = nextState->handleEvent(event, param);}}}private:HSMState* m_currentState;void initialize(HSMState* initialState) {if (initialState != nullptr) {// 初始化状态栈QVector<HSMState*> stateStack;while (initialState != nullptr) {stateStack.append(initialState);initialState = initialState->parent();}// 从顶层状态开始初始化for (int i = stateStack.size() - 1; i >= 0; --i) {HSMState* currentState = stateStack[i];currentState->handleEvent(HSMUtilityDef::HSME_ENTRY, nullptr);}m_currentState = stateStack.last();}}HSMState* processSingleEvent(HSMState* currentState, HSMUtilityDef::HSM_EVENT event, void* param) {switch (event) {case HSMUtilityDef::HSME_INIT:return initializeChildStates(currentState);case HSMUtilityDef::HSME_ENTRY:currentState->onEntry(param);break;case HSMUtilityDef::HSME_EXIT:currentState->onExit(param);return processSingleEvent(currentState->parent(), HSMUtilityDef::HSME_EXIT, param);}return currentState;}HSMState* initializeChildStates(HSMState* parentState) {if (parentState == nullptr) {return nullptr;}QVector<HSMState*> childStates = findInitialStates(parentState);for (HSMState* state : childStates) {processSingleEvent(state, HSMUtilityDef::HSME_ENTRY, nullptr);}return childStates.last();}QVector<HSMState*> findInitialStates(HSMState* parentState) const {// 在实际应用中,可能需要更复杂的逻辑来确定初始子状态// 这里简单地假设每个父状态只有一个直接的初始子状态QVector<HSMState*> children;QObjectList childObjects = parentState->children();for (QObject* obj : childObjects) {HSMState* state = qobject_cast<HSMState*>(obj);if (state != nullptr) {children.append(state);}}// 返回第一个子状态作为初始状态return children;}
};
构建和运行状态机
在 main
函数中构建并运行层次状态机:
#include <QCoreApplication>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 创建状态对象StandbyState* standby = new StandbyState();RunningState* running = new RunningState(standby);ChannelSelectionState* channelSel = new ChannelSelectionState(running);VolumeControlState* volumeCtrl = new VolumeControlState(running);// 构建层次结构running->setParent(standby);channelSel->setParent(running);volumeCtrl->setParent(running);// 创建状态机并启动HSM hsm;hsm.start(standby);// 处理事件hsm.processEvent(HSMUtilityDef::POWER); // 切换到运行模式hsm.processEvent(HSMUtilityDef::CHANNEL_UP); // 选择频道向上hsm.processEvent(HSMUtilityDef::MODE_SWITCH); // 切换到锁定模式hsm.processEvent(HSMUtilityDef::VOLUME_UP); // 增加音量hsm.processEvent(HSMUtilityDef::POWER); // 关闭电视return a.exec();
}
4. 使用 Qt 的信号和槽机制增强状态机
Qt 提供了强大的信号和槽机制,可以用来进一步简化状态机的设计和实现。以下是如何将 Qt 的信号和槽与层次状态机结合使用的方法。
修改 HSMState
类以支持信号和槽
在 HSMState
中添加信号来通知状态转换或动作执行:
#include <QObject>
#include <QVector>
#include <QDebug>namespace HSMUtilityDef {typedef uint32_t HSM_EVENT;// 定义常见事件const uint32_t MAX_DEPTH = 5;const HSM_EVENT HSME_NULL = 0;const HSM_EVENT HSME_START = 1;const HSM_EVENT HSME_INIT = static_cast<HSM_EVENT>(-3);const HSM_EVENT HSME_ENTRY = static_cast<HSM_EVENT>(-2);const HSM_EVENT HSME_EXIT = static_cast<HSM_EVENT>(-1);// 自定义事件const HSM_EVENT POWER = 100;const HSM_EVENT CHANNEL_UP = 101;const HSM_EVENT CHANNEL_DOWN = 102;const HSM_EVENT VOLUME_UP = 103;const HSM_EVENT VOLUME_DOWN = 104;const HSM_EVENT MODE_SWITCH = 105;
}class HSMState : public QObject {Q_OBJECTpublic:explicit HSMState(HSMState *parent = nullptr) : QObject(parent), m_parent(parent) {}virtual ~HSMState() {}// 处理事件的主要接口virtual HSMUtilityDef::HSM_EVENT handleEvent(HSMUtilityDef::HSM_EVENT event, void* param = nullptr) {switch (event) {case HSMUtilityDef::HSME_ENTRY:onEntry(param);break;case HSMUtilityDef::HSME_EXIT:onExit(param);break;default:return unhandledEvent(event, param);}return HSMUtilityDef::HSME_NULL;}signals:// 信号用于通知状态转换或动作执行void stateEntered(HSMState* state);void stateExited(HSMState* state);protected:// 进入状态时执行的动作virtual void onEntry(void* param) {emit stateEntered(this);}// 离开状态时执行的动作virtual void onExit(void* param) {emit stateExited(this);}// 处理未定义事件的方法virtual HSMUtilityDef::HSM_EVENT unhandledEvent(HSMUtilityDef::HSM_EVENT event, void* param) {qDebug() << "Unhandled event" << event;return event;}// 获取父状态HSMState* parent() const { return m_parent; }private:HSMState *m_parent;
};