【Qt/C++编程】基于Qt的状态机实现

基于Qt封装的轻量型状态机

这篇文章分析基于Qt封装的状态机,贴合Qt的信号槽可灵活高效的管理状态解决方案。

状态机概述

整个状态机框架由几个核心类组成:

  • StateObject代表状态对象
  • StateWatcher用于监听状态变化
  • StateManager作为核心管理类
  • EmptyStateObject作为特殊空状态

状态机采用单例模式管理状态,通过全局的state()函数访问状态管理器。


状态对象的设计

StateObject类是整个框架的基础单元,它继承自QObject以获得Qt的信号槽功能。每个状态对象包含几个关键属性:

  • 状态名称(name):用于标识不同状态

  • 前驱状态(previousState)和后继状态(nextState):构成状态流转关系

  • 可变数据(var&data):允许状态携带自定义数据

方法 / 信号 参数 返回值 说明
构造函数 name(状态名), previous_state, next_state, parent - 创建一个状态对象
name() - QString 获取状态名称
previousState() - StateObject* 获取前驱状态(若不存在则返回空状态)
setPreviousState(StateObject*, bool) previous_state, is_bidirectional(是否双向关联) void 设置前驱状态
nextState() - StateObject* 获取后继状态(若不存在则返回空状态)
setNextState(StateObject*, bool) next_state, is_bidirectional void 设置后继状态
var() - QVariant 获取状态关联的数据
setVar(QVariant) var(自定义数据) void 设置状态数据
信号 rein(StateObject*) from(来源状态) - 进入该状态时触发
信号 raus(StateObject*) to(目标状态) - 离开该状态时触发
#include 
#include 
#include 

#include 

#if defined(STATE_LIBRARY)
#  define STATESHARED_EXPORT Q_DECL_EXPORT
#else
#  define STATESHARED_EXPORT Q_DECL_IMPORT
#endif
namespace imf {
class STATESHARED_EXPORT StateObject : public QObject {
Q_OBJECT
public:
	explicit StateObject(const QString& name, StateObject * prev = nullptr, StateObject * next = nullptr, QObject * p = nullptr);
	virtual bool isEmptyState() { return false;}
	QString name() const;
	StateObject * prev() const;
	virtual void setPrevState(StateObject * prev, bool is_bidirectional = true);
	StateObject * next() const;
	virtual void setNextState(StateObject * next, bool is_bidirectional = true)
	QVaraint data() const;
	virtual void setData(const QVariant& data);
signals:
	void into(imf::StateObject * from);
	void outfrom(imf::StateObject * to);
private:
	QString m_name;
	StateObject * m_prev;
	StateObject * m_next;
	QVariant m_data;
};

class STATESHARED_EXPORT EmptyStateObject : public StateObject {
Q_OBJECT
public:
    explicit EmptyStateObject(QObject *parent = nullptr) : StateObject("@e", nullptr, nullptr, parent) {}

    bool isEmptyState() override {return true;}

    void setPrevState(StateObject *, bool) override {}
    void setNextState(StateObject *, bool) override {}
    void setData(const QVariant &) override {}
};

class STATESHARED_EXPORT StateWatcher : QObject {
Q_OBJECT
public:
	explicit StateWatcher(QObject * p = nullptr);
signals:
	void changed(imf::StateObject * from, imf::StateObject * to);
};

状态管理者

方法 参数 返回值 说明
构造函数 parent - 初始化状态管理器
instance() - StateManager& 获取单例实例
emptyState() - EmptyStateObject* 获取全局空状态
emptyWatcher() - StateWatcher* 获取全局空观察者
regist(QObject*, QString, bool) context, state_name, is_current StateObject* 注册单个状态
regist(QObject*, QStringList, bool, ConnectionType) context, state_names, first_is_current, connection_type bool 批量注册状态,并指定连接方式
cancel(QObject*, QString) context, state_name(若空则删除所有) bool 注销状态
get(QObject*, QString) context, state_name StateObject* 获取指定状态(不存在则返回空状态)
current(QObject*) context StateObject* 获取当前状态
change(QObject*, StateObject*) context, state_obj void 切换状态
change(QObject*, QString) context, state_name void 按名称切换状态
toNext(QObject*) context void 切换到下一个状态
toPrevious(QObject*) context void 切换到上一个状态
watcher(QObject*) context StateWatcher* 获取该上下文的观察者
class CORESHARED_EXPORT StateManager : public QObject
{
    Q_OBJECT

public:
    enum ConnectionType {
        NO_CONNECTION,
        SEQUENTIAL_CONNECTION,
        LOOP_CONNECTION,
        CROSS_CONNECTION
    };

    explicit StateManager(QObject *parent = nullptr);
    static StateManager & instance();

    EmptyStateObject * emptyState() const;
    StateWatcher * emptyWatcher() const;

    StateObject * regist(QObject *context, const QString &state_name, bool is_current = false);
    bool regist(QObject *context, const QStringList &state_names, bool first_is_current = true, ConnectionType connection_type = SEQUENTIAL_CONNECTION);
    bool cancel(QObject *context, const QString &state_name = "");

    StateObject *get(QObject *context, const QString &state_name) const;

    StateObject *current(QObject *context) const;

    void change(QObject *context, StateObject *state_obj);
    void change(QObject *context, const QString &state_name);
    void toNext(QObject *context);
    void toPrevious(QObject *context);

    StateWatcher *watcher(QObject *context) const;

signals:

public slots:

private:
    EmptyStateObject *m_empty_state;
    StateWatcher *m_empty_watcher;

    QHash<QObject *, QHash<QString, StateObject *> *> m_states;
    QHash<QObject *, StateObject *> m_cur_state_hash;
    QHash<QObject *, StateWatcher *> m_watcher_hash;
};

STATESHARED_EXPORT imf::StateManager & state();

设计亮点

  • 上下文隔离:通过context参数,同一状态机可以服务多个不同模块,彼此状态互不干扰。
  • 灵活的状态连接:支持多种状态连接方式,可以构建复杂的状态流转关系。
  • 安全的空状态:通过专门的空状态对象避免了空指针异常。
  • 观察者模式:内置状态变化通知机制,便于扩展。
  • 双向关联维护:设置前驱/后继状态时自动维护双向关系,确保状态链一致性。

使用方法

class Work : public QObject {...};

Work::Work(...) {
	state().regist(this, QList<QString>() << "a" << "b" << "c");
	state().change(this, "a");
	connect(state().watcher(this), &imf::StateWatcher::changed, this, 
	[=](imf::StateObject*, imf::StateObject* ) {
		//Do your work.
	});
}

你可能感兴趣的:(Qt有关一些设计和知识,qt,c++)