命令模式封装请求以解耦发送者与接收者,策略模式封装算法以实现运行时替换。命令模式的核心在于将请求封装为对象,使能支持撤销、日志、排队等功能,主要涉及command、concretecommand、receiver、invoker和client五个角色;而策略模式通过封装不同的算法族,允许算法独立变化并可在运行时切换,核心在于算法的可替换性。两者虽均基于接口设计思想,但应用场景不同:命令模式适用于gui操作、事务处理、游戏动作记录等需保存或撤销请求的场景,策略模式则适用于支付方式、排序算法等需动态切换行为的场景。

C++命令模式的核心在于将请求封装成一个对象,从而允许你参数化客户端对象,支持请求排队、记录请求日志,以及支持可撤销的操作。简单来说,就是把“做什么”和“谁去做”解耦。

解决方案

命令模式涉及几个关键角色:
立即学习“C++免费学习笔记(深入)”;

以下是一个简单的C++命令模式示例:
#include <iostream>
#include <vector>
// Receiver
class Light {
public:
void turnOn() {
std::cout << "Light is ON" << std::endl;
}
void turnOff() {
std::cout << "Light is OFF" << std::endl;
}
};
// Command Interface
class Command {
public:
virtual void execute() = 0;
virtual ~Command() {}
};
// Concrete Command
class TurnOnCommand : public Command {
private:
Light* light;
public:
TurnOnCommand(Light* light) : light(light) {}
void execute() override {
light->turnOn();
}
};
// Concrete Command
class TurnOffCommand : public Command {
private:
Light* light;
public:
TurnOffCommand(Light* light) : light(light) {}
void execute() override {
light->turnOff();
}
};
// Invoker
class RemoteControl {
private:
std::vector<Command*> commands;
public:
void setCommand(Command* command) {
commands.push_back(command);
}
void pressButton() {
if (!commands.empty()) {
commands.back()->execute();
commands.pop_back(); // 执行后移除,简化示例
} else {
std::cout << "No command set" << std::endl;
}
}
};
int main() {
Light* livingRoomLight = new Light();
TurnOnCommand* turnOnCmd = new TurnOnCommand(livingRoomLight);
TurnOffCommand* turnOffCmd = new TurnOffCommand(livingRoomLight);
RemoteControl* remote = new RemoteControl();
remote->setCommand(turnOnCmd);
remote->setCommand(turnOffCmd);
remote->pressButton(); // Light is OFF (因为后设置的是TurnOffCommand)
remote->pressButton(); // Light is ON
delete turnOnCmd;
delete turnOffCmd;
delete livingRoomLight;
delete remote;
return 0;
}这个例子中,Light是接收者,TurnOnCommand和TurnOffCommand是具体命令,RemoteControl是调用者。 客户端负责创建命令并将它们传递给调用者。
命令模式在C++中有什么实际应用场景?
命令模式在GUI应用程序、事务处理、宏记录、以及游戏开发中都有广泛应用。例如,在文本编辑器中,每个操作(如复制、粘贴、删除)都可以封装成一个命令对象。这样做的好处是,可以很容易地实现撤销/重做功能,只需要维护一个命令历史记录即可。此外,命令模式还可以用于实现复杂的事务处理,确保一系列操作要么全部成功执行,要么全部回滚。 在游戏开发中,玩家的每一个操作(如移动、攻击)都可以视为一个命令,便于记录和回放。
C++中如何实现命令的撤销(Undo)和重做(Redo)?
实现撤销和重做功能,需要在Command接口中添加undo()方法,并在ConcreteCommand中实现该方法。同时,需要维护一个命令历史栈,用于记录已执行的命令。
// Command Interface (with Undo)
class Command {
public:
virtual void execute() = 0;
virtual void undo() = 0; // 添加 undo 方法
virtual ~Command() {}
};
// Concrete Command (with Undo)
class TurnOnCommand : public Command {
private:
Light* light;
bool previousState; // 记录之前的状态,以便 undo
public:
TurnOnCommand(Light* light) : light(light), previousState(false) {}
void execute() override {
previousState = (/*假设Light有个getState()方法*/ false); // 实际应用中需要获取灯的当前状态
light->turnOn();
}
void undo() override {
if (previousState) {
light->turnOn(); // 恢复到之前的状态(如果之前是开着的)
} else {
light->turnOff(); // 恢复到之前的状态(如果之前是关着的)
}
}
};
//Invoker (with Undo/Redo)
class RemoteControl {
private:
std::vector<Command*> commandHistory;
int currentCommandIndex = -1; // 指向当前执行的命令
public:
void executeCommand(Command* command) {
command->execute();
if (currentCommandIndex < (int)commandHistory.size() - 1) {
// 如果执行了undo之后的新命令,则清除后面的历史
commandHistory.erase(commandHistory.begin() + currentCommandIndex + 1, commandHistory.end());
}
commandHistory.push_back(command);
currentCommandIndex++;
}
void undo() {
if (currentCommandIndex >= 0) {
commandHistory[currentCommandIndex]->undo();
currentCommandIndex--;
}
}
void redo() {
if (currentCommandIndex < (int)commandHistory.size() - 1) {
currentCommandIndex++;
commandHistory[currentCommandIndex]->execute();
}
}
};
int main() {
Light* livingRoomLight = new Light();
RemoteControl* remote = new RemoteControl();
TurnOnCommand* turnOnCmd = new TurnOnCommand(livingRoomLight);
TurnOffCommand* turnOffCmd = new TurnOffCommand(livingRoomLight);
remote->executeCommand(turnOnCmd); // Light is ON
remote->executeCommand(turnOffCmd); // Light is OFF
remote->undo(); // Light is ON
remote->undo(); // Light is OFF
remote->redo(); // Light is ON
remote->redo(); // Light is OFF
delete turnOnCmd;
delete turnOffCmd;
delete livingRoomLight;
delete remote;
return 0;
}注意,undo()的实现需要根据具体情况进行调整,通常需要记录命令执行前的状态。此外,撤销/重做功能的实现还需要考虑内存管理,避免内存泄漏。
命令模式和策略模式有什么区别?
虽然命令模式和策略模式都涉及到封装,但它们的目的不同。命令模式封装的是请求,而策略模式封装的是算法。 命令模式的重点在于解耦请求的发送者和接收者,允许请求排队、记录日志等。 策略模式的重点在于提供一种在运行时选择算法的方式,使得算法可以独立于使用它的客户端而变化。 策略模式关注的是算法的可替换性,而命令模式关注的是请求的封装和执行。 简单来说,策略模式解决的是“用哪个算法”,命令模式解决的是“做什么操作”。
以上就是C++如何实现命令模式 C++命令模式的设计与示例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号