【开发语言】层次状态机(HSM)介绍

层次状态机(Hierarchical State Machine, HSM),从基本原理、结构设计、实现方法以及如何结合 Qt 进行具体实现等方面进行分析。

1. 层次状态机的基本原理

层次状态机是一种用于管理复杂系统行为的状态机模型,它通过将状态组织成层次结构来简化设计和维护。这种结构使得复杂的逻辑可以分解为更小、更易于管理的部分。

关键概念:
  • 状态(State): 系统在某一时刻所处的条件或模式。
  • 事件(Event): 触发状态转换的信息或信号。
  • 转换(Transition): 从一个状态到另一个状态的迁移过程。
  • 动作(Action): 在进入、离开状态或进行转换时执行的操作。
  • 父状态和子状态 :
    • 父状态(Superstate): 包含多个子状态的状态。
    • 子状态(Substate): 属于某个父状态的更具体的状态。
特点:
  • 嵌套结构: 状态可以嵌套在其他状态中,形成层次结构。
  • 继承行为: 子状态可以继承父状态的行为和动作。
  • 事件委托: 事件可以从子状态传递到父状态进行处理。
  • 简化设计: 将复杂的状态逻辑分解为更小的、可管理的部分。

2. 层次状态机的设计

在设计层次状态机时,需要仔细规划状态之间的关系以及如何组织这些状态。以下是一些设计原则和步骤:

设计步骤:
  1. 识别顶级状态:

    • 确定系统的基本操作模式或主要功能。
    • 例如,在一个电梯系统中,顶级状态可能包括"待命"、"运行"和"维护"。
  2. 定义子状态:

    • 对于每个顶级状态,进一步分解为更具体的状态。
    • 例如,"运行"状态可以包含"上升"、"下降"和"停止"等子状态。
  3. 确定事件和转换:

    • 定义可能触发状态转换的事件。
    • 确定每个状态在接收到特定事件时应执行的操作以及如何进行转换。
    • 例如,"上升"状态在接收到"到达楼层"事件时,可以转换到"停止"状态。
  4. 实现继承和委托:

    • 设计父状态的行为,并让子状态继承这些行为。
    • 当子状态无法处理某个事件时,将该事件传递给其父状态进行处理。
  5. 编写动作函数:

    • 实现每个状态的进入(Entry)、离开(Exit)操作以及转换期间的动作(Action)。
    • 例如,在"上升"状态下进入时启动电机,在离开时停止电机。
  6. 定义初始状态和历史状态:

    • 指定每个复合状态的初始子状态。
    • 使用历史状态来记住上次活动的子状态,以便在返回该状态时恢复到之前的状态。
示例:

假设我们设计一个简单的电视遥控器状态机,包含以下状态:

  • 待命(Standby)
  • 运行(Running)
    • 频道选择(Channel Selection)
      • 浏览模式(Browse Mode)
      • 锁定模式(Lock Mode)
    • 音量控制(Volume Control)

事件包括:

  • 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 的具体示例。

使用结构体定义状态和事件

首先,我们定义状态、事件及其处理函数的类型:

cpp 复制代码
#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,包含处理事件的虚函数:

cpp 复制代码
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;
};
定义具体状态类

创建具体的派生状态类,实现特定的逻辑:

cpp 复制代码
// 待命状态(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

cpp 复制代码
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 函数中构建并运行层次状态机:

cpp 复制代码
#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 中添加信号来通知状态转换或动作执行:

cpp 复制代码
#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;
};
相关推荐
猷咪11 小时前
C++基础
开发语言·c++
IT·小灰灰11 小时前
30行PHP,利用硅基流动API,网页客服瞬间上线
开发语言·人工智能·aigc·php
快点好好学习吧11 小时前
phpize 依赖 php-config 获取 PHP 信息的庖丁解牛
android·开发语言·php
秦老师Q11 小时前
php入门教程(超详细,一篇就够了!!!)
开发语言·mysql·php·db
烟锁池塘柳011 小时前
解决Google Scholar “We‘re sorry... but your computer or network may be sending automated queries.”的问题
开发语言
是誰萆微了承諾11 小时前
php 对接deepseek
android·开发语言·php
2601_9498683611 小时前
Flutter for OpenHarmony 电子合同签署App实战 - 已签合同实现
java·开发语言·flutter
星火开发设计11 小时前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
qq_1777673711 小时前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
一匹电信狗11 小时前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl