【开发语言】层次状态机(HSM)介绍
层次状态机(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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_NULL
while (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_OBJECT
public:
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;
};