多任务响应1(Qt)

多任务响应1

  • 1. 架构概述
  • 2. 代码示例
  • 3. 说明

当系统的一些任务都是同一个对象产生,但需要交由不同对象进行响应。
比如:系统有多个按键,这些按键的共用一个槽函数,但不同的按键对应不同的功能响应。

推荐采用命令模式+分散响应的思想。在这种设计中,

  • 每个按键对应一个实现了统一接口(如 ICommand)的命令对象,

  • 每个命令负责单一的功能,符合单一职责原则;

  • 一个中心的 CommandManager 用于注册和管理命令,根据传入的命令标识执行对应操作;

  • 按键的 clicked 信号通过 lambda 表达式与 CommandManager 的执行接口绑定,从而实现分散响应。

下面分为三个部分介绍:

1. 架构概述

设计思想:

  • 解耦与扩展性: 每个功能都有独立的命令对象,新增或修改按键响应只需要新增或修改对应命令,而不必改动整体分发逻辑;

  • 统一管理: CommandManager 统一管理各个命令对象,与 UI 层解耦。利用 Qt 的信号和槽,UI 层只需负责转发按键事件;

  • 灵活性: 利用 C++17 的特性(如 lambda 表达式、std::unique_ptr 等),使代码更加现代化和健壮。

架构示意图:

[UI按钮]
    │ clicked()
    ▼
[Lambda表达式]
    │ 调用
    ▼
[CommandManager] ---- 查找命令 ----> [ICommand] ---> 执行具体功能

2. 代码示例

以下是一个完整的示例代码,包括命令接口、具体命令实现、命令管理器以及如何在 Qt 的主窗口中连接按钮信号。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// 1. 定义命令接口
class ICommand {
public:
    virtual ~ICommand() = default;
    virtual void execute() = 0;
};

// 2. 具体命令实现(示例:启动和停止操作)
class SpindleStartCommand : public ICommand {
public:
    void execute() override {
        qDebug() << "Spindle started.";
        // 此处添加数控软件启动主轴等操作的具体实现
    }
};

class SpindleStopCommand : public ICommand {
public:
    void execute() override {
        qDebug() << "Spindle stopped.";
        // 此处添加数控软件停止主轴等操作的具体实现
    }
};

// 3. 命令管理器,用于注册和执行命令
class CommandManager {
public:
    using CommandPtr = std::unique_ptr<ICommand>;

    // 注册命令,commandName 作为标识
    void registerCommand(const QString &commandName, CommandPtr command) {
        commands_[commandName] = std::move(command);
    }

    // 根据命令名称执行对应命令
    void executeCommand(const QString &commandName) {
        auto it = commands_.find(commandName);
        if (it != commands_.end()) {
            it->second->execute();
        } else {
            qWarning() << "Command not found:" << commandName;
        }
    }

private:
    std::unordered_map<QString, CommandPtr> commands_;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    // 主窗口及布局
    QWidget window;
    window.setWindowTitle("数控软件示例");
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // 创建两个示例按钮
    QPushButton *btnStart = new QPushButton("启动主轴");
    QPushButton *btnStop  = new QPushButton("停止主轴");

    layout->addWidget(btnStart);
    layout->addWidget(btnStop);

    // 4. 初始化命令管理器并注册具体命令
    CommandManager commandManager;
    commandManager.registerCommand("start", std::make_unique<SpindleStartCommand>());
    commandManager.registerCommand("stop", std::make_unique<SpindleStopCommand>());

    // 5. 连接按钮信号到命令执行,通过 lambda 调用 CommandManager 对应方法
    QObject::connect(btnStart, &QPushButton::clicked, [&commandManager]() {
        commandManager.executeCommand("start");
    });
    QObject::connect(btnStop, &QPushButton::clicked, [&commandManager]() {
        commandManager.executeCommand("stop");
    });

    window.show();
    return app.exec();
}

3. 说明

  • 模块化设计:
    每个具体命令(例如 SpindleStartCommand、SpindleStopCommand)只负责它自己的功能,后续添加新功能时,只需新建命令类并在 CommandManager 中注册,不用修改原有代码。

  • 使用 Qt 信号槽机制:
    利用 lambda 表达式直接在连接中调用 CommandManager 的 executeCommand 方法,使得连接逻辑非常直观,不需要中间的 QSignalMapper。

  • 扩展性:
    如果今后需要新增其他控制功能,只需要实现继承 ICommand 的新命令类,然后在界面中添加对应按钮或其他触发器,通过 CommandManager 注册并连接对应命令即可。

  • C++17特性:
    示例中使用了 std::unique_ptr 来管理命令对象以及 lambda 表达式,使得代码更加现代化,同时降低资源管理的复杂度

你可能感兴趣的:(Qt笔记,软件架构,qt)