多任务响应2
- 扩展方案
- 1. 设计思路
- 2. 示例代码
- 3. 说明
在多任务响应1的基础上,当任务响应比较复杂时,需要整合多个模块的信息。
扩展方案
利用【中介者模式】或【系统上下文】来整合多个模块的信息,并在命令对象中通过依赖注入(Dependency Injection)的方式获取这些模块的接口。这样,复杂响应的命令对象就可以根据需要同时访问多个模块,从而实现更复杂的业务逻辑。同时,这种设计依然满足模块化和解耦的要求,便于后续扩展和维护。
1. 设计思路
(1)创建模块接口
为各个具体业务模块定义接口(例如 IModuleA、IModuleB),以便于命令对象只依赖于接口而非具体实现。
(2)构建系统上下文
建立一个系统上下文(SystemContext)类来汇集所有模块的指针或者引用。通过将上下文注入到命令对象中,命令可以便捷地获取多个模块的信息,完成复杂的业务响应。
(3)实现复杂命令
复杂命令(例如 ComplexCommand)将依赖 SystemContext,在 execute() 方法中调用所依赖的各个模块,从而实现跨模块的信息整合与操作。
(4)信号槽结合
在 Qt 的信号槽机制中,按键的响应仍然通过 lambda 表达式调用 CommandManager 的 executeCommand()。而 CommandManager 内部已经注册了需要复杂响应的命令,该命令已被注入 SystemContext,从而可以访问所有必要模块。
2. 示例代码
#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QDebug>
#include <QString>
#include <unordered_map>
#include <memory>
// ==========================
// 1. 定义基础命令接口
class ICommand {
public:
virtual ~ICommand() = default;
virtual void execute() = 0;
};
// ==========================
// 2. 定义模块接口和实现
// 模块A接口和实现(例如负责生产某种数据)
class IModuleA {
public:
virtual ~IModuleA() = default;
virtual QString getInfoA() const = 0;
};
class ModuleA : public IModuleA {
public:
QString getInfoA() const override {
return "ModuleA 数据";
}
};
// 模块B接口和实现(例如负责控制硬件或执行特定操作)
class IModuleB {
public:
virtual ~IModuleB() = default;
virtual QString getInfoB() const = 0;
};
class ModuleB : public IModuleB {
public:
QString getInfoB() const override {
return "ModuleB 数据";
}
};
// ==========================
// 3. 定义系统上下文,将各模块整合到一起
class SystemContext {
public:
SystemContext(IModuleA* modA, IModuleB* modB)
: moduleA(modA), moduleB(modB) {}
IModuleA* getModuleA() const { return moduleA; }
IModuleB* getModuleB() const { return moduleB; }
private:
IModuleA* moduleA;
IModuleB* moduleB;
};
// ==========================
// 4. 实现一个复杂命令,该命令依赖多个模块的信息
class ComplexCommand : public ICommand {
public:
// 注入 SystemContext
ComplexCommand(SystemContext* ctx) : context(ctx) {}
void execute() override {
// 从上下文中获取各模块信息
QString infoA = context->getModuleA()->getInfoA();
QString infoB = context->getModuleB()->getInfoB();
qDebug() << "执行复杂命令,整合信息: " << infoA << "和" << infoB;
// 此处可以添加更复杂的逻辑,例如数据交互、状态修改等。
}
private:
SystemContext* context;
};
// ==========================
// 5. 命令管理器:注册并根据名称调度命令
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() << "未找到命令:" << commandName;
}
}
private:
std::unordered_map<QString, CommandPtr> commands_;
};
// ==========================
// 6. 主函数中构建各模块、上下文、注册命令并连接信号
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// 创建主窗口与布局
QWidget window;
window.setWindowTitle("数控软件复杂响应示例");
QVBoxLayout *layout = new QVBoxLayout(&window);
// 创建示例按钮:简单命令和复杂命令
QPushButton *btnSimple = new QPushButton("简单命令");
QPushButton *btnComplex = new QPushButton("复杂命令");
layout->addWidget(btnSimple);
layout->addWidget(btnComplex);
// 初始化 CommandManager
CommandManager commandManager;
// 注册一个简单命令作为对比(例如启动命令)
class SimpleCommand : public ICommand {
public:
void execute() override {
qDebug() << "执行简单命令:启动操作";
}
};
commandManager.registerCommand("simple", std::make_unique<SimpleCommand>());
// 构建各个模块实例(实际项目中一般为单例或通过依赖注入框架管理)
auto moduleA = std::make_unique<ModuleA>();
auto moduleB = std::make_unique<ModuleB>();
// 构建系统上下文,注入各模块接口
SystemContext context(moduleA.get(), moduleB.get());
// 注册复杂命令,并将 SystemContext 注入命令中
commandManager.registerCommand("complex", std::make_unique<ComplexCommand>(&context));
// 连接按钮信号,通过 lambda 表达式调用 CommandManager 的执行接口
QObject::connect(btnSimple, &QPushButton::clicked, [&commandManager]() {
commandManager.executeCommand("simple");
});
QObject::connect(btnComplex, &QPushButton::clicked, [&commandManager]() {
commandManager.executeCommand("complex");
});
window.show();
return app.exec();
}
3. 说明
-
模块接口与实现
为 ModuleA 和 ModuleB 分别定义了接口 IModuleA/IModuleB,并提供了简单的示例实现。实际项目中,这些模块可能负责数据采集、硬件控制、状态监控等复杂任务。 -
系统上下文(SystemContext)
将所有模块聚合在一个上下文对象中后,可以在复杂命令中直接获取到所有需要的信息,这样即使复杂命令跨越多个模块,也不需要频繁修改命令接口。 -
复杂命令 ComplexCommand
通过构造函数注入 SystemContext,在 execute() 中直接访问各模块信息,并根据获得的信息来实现需要的业务逻辑。 -
命令管理器与信号槽
与前面的命令模式示例类似,CommandManager 依旧负责注册和调用命令。按钮点击后,通过 lambda 表达式调用相应命令的 execute() 方法。这样,UI 部分无需关心具体的模块依赖问题,所有复杂逻辑都封装在命令对象内部。 -
扩展性
如果将来某个功能响应需要更多模块,只需在 SystemContext 中添加相应模块或扩展接口即可;同时,相应的命令类也可以做相应调整,而无需改动其他模块或 CommandManager 的实现。