命令模式(Command Pattern)★
命令模式(Command Pattern)
如果任务有多个复杂的操作,可以使用命令模式将任务的操作封装为命令对象。这些命令对象可以在需要时按顺序执行,方便管理任务执行的逻辑和回滚操作。
示例:
class Command {
public:
virtual void execute() = 0; // 执行命令
};
class RunTaskCommand : public Command {
private:
Task *task;
public:
RunTaskCommand(Task *task) : task(task) {}
void execute() override {
task->runTask();
}
};
命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而使用户可用不同的请求对客户进行参数化。它还可以将请求排队、记录请求日志,以及支持可撤销的操作。以下是对命令模式的详细解释,以及如何理解它的用途。
命令模式的核心概念
-
Command(命令接口):
- 定义了一个执行操作的接口,通常包含一个
execute()
方法。 - 所有具体命令类都实现这个接口。
- 定义了一个执行操作的接口,通常包含一个
-
ConcreteCommand(具体命令类):
- 实现了 Command 接口,具体执行某个操作。
- 通常包含一个对 Receiver(接收者)的引用,调用 Receiver 的方法来完成实际操作。
-
Receiver(接收者):
- 实际执行操作的对象。
- 具体命令类会调用 Receiver 的方法来完成实际操作。
-
Invoker(调用者):
- 要求命令执行这个请求的对象。
- 它调用命令对象的
execute()
方法,但并不知道具体的命令逻辑。
-
Client(客户端):
- 创建具体命令对象,并将具体命令对象和接收者对象组装在一起。
- 客户端将命令对象传递给调用者对象。
示例代码解析
以下是一个完整的命令模式示例,包括命令接口、具体命令类、接收者类和调用者类。
1. 命令接口(Command)
class Command {
public:
virtual ~Command() {}
virtual void execute() = 0; // 执行命令
};
2. 接收者类(Receiver)
class Task {
public:
virtual ~Task() {}
virtual void runTask() = 0; // 实际执行的任务
};
3. 具体任务类(Concrete Receiver)
class MetricTask : public Task {
public:
void runTask() override {
std::cout << "Executing Metric Task" << std::endl;
}
};
class MillimeterTask : public Task {
public:
void runTask() override {
std::cout << "Executing Millimeter Task" << std::endl;
}
};
4. 具体命令类(Concrete Command)
class RunTaskCommand : public Command {
private:
Task* task;
public:
RunTaskCommand(Task* task) : task(task) {}
void execute() override {
task->runTask();
}
};
5. 调用者类(Invoker)
class TaskInvoker {
private:
Command* command;
public:
void setCommand(Command* cmd) {
command = cmd;
}
void executeCommand() {
if (command) {
command->execute();
}
}
};
使用示例
以下是如何使用命令模式来执行任务的示例:
#include <iostream>
int main() {
// 创建具体的任务对象
MetricTask metricTask;
MillimeterTask millimeterTask;
// 创建具体的命令对象,并将任务对象传递给命令对象
RunTaskCommand metricCommand(&metricTask);
RunTaskCommand millimeterCommand(&millimeterTask);
// 创建调用者对象,并将命令对象传递给调用者
TaskInvoker invoker;
invoker.setCommand(&metricCommand);
invoker.executeCommand(); // 输出: Executing Metric Task
invoker.setCommand(&millimeterCommand);
invoker.executeCommand(); // 输出: Executing Millimeter Task
return 0;
}
输出
Executing Metric Task
Executing Millimeter Task
命令模式的用途
-
解耦客户端和接收者:
- 客户端(调用者)不需要直接调用接收者的方法,而是通过命令对象间接调用。这使得客户端和接收者之间解耦,客户端不需要知道具体的实现细节。
-
支持撤销和重做操作:
- 命令模式可以扩展为支持撤销和重做操作。通过在命令对象中保存操作前的状态,可以在需要时撤销操作。
-
支持命令队列和日志记录:
- 命令对象可以被存储在队列中,按顺序执行。同时,命令对象可以记录执行的操作,便于日志记录和审计。
-
支持宏命令:
- 可以将多个命令组合成一个宏命令,通过一个命令对象来执行多个操作。
总结
命令模式的核心在于将请求封装为一个对象,从而实现解耦和扩展性。通过命令模式,客户端可以不知道具体的实现细节,同时支持撤销、重做、命令队列和日志记录等功能。希望这个解释和示例能帮助你更好地理解命令模式的用途和实现方式。