命令模式封装请求以解耦发送者与接收者,策略模式封装算法以实现运行时替换。命令模式的核心在于将请求封装为对象,使能支持撤销、日志、排队等功能,主要涉及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号