当前位置: 首页 > article >正文

【开发语言】层次状态机(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 的具体示例。

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

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

#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;
};


http://www.kler.cn/a/421522.html

相关文章:

  • 有趣的Docker
  • Java - JSR223规范解读_在JVM上实现多语言支持
  • 【C++】深入优化计算题目分析与实现
  • JAVA设计模式,动态代理模式
  • 6.824/6.5840(2024)环境配置wsl2+vscode
  • java将word docx pdf转换为图片(不需要额外下载压缩包,直接导入maven坐标)
  • 【学习Go编程】
  • 数据结构有哪些?
  • Redis+Caffeine 多级缓存数据一致性解决方案
  • 杂七杂八的网络安全知识
  • 【iOS】设计模式的六大原则
  • qt QGraphicsRotation详解
  • 分层架构 IM 系统之 Router 架构分析
  • Elastic Cloud Serverless:深入探讨大规模自动扩展和性能压力测试
  • 重学设计模式-工厂模式(简单工厂模式,工厂方法模式,抽象工厂模式)
  • 数据结构—队列
  • 顶刊算法 | 鱼鹰算法OOA-BiTCN-BiGRU-Attention多输入单输出回归预测(Maltab)
  • Zabbix添加防火墙温度监控值实战
  • Macos用brew安装Nodejs亲手教程
  • LLM与动态符号执行生成测试用例的比较
  • C语言第十五周课——课堂练习
  • 数据结构自测题1
  • Qt 5 中的 QTextStream 使用指南
  • 接口自动化测试框架(pytest+allure+aiohttp+用例自动生成)
  • 正则表达式解析
  • ceph mon 数据重建