命令模式(Command Pattern)是一种行为型设计模式,其核心思想是 将请求封装为一个对象(命令),使请求的发送者与接收者解耦。通过命令对象,发送者无需知道接收者的具体实现,只需调用命令的执行方法即可,同时支持对命令的撤销、排队、日志记录等扩展操作。
一、介绍
核心角色
- 命令(Command)
定义执行操作的接口,通常包含一个抽象的execute()
方法(用于执行命令)和undo()
方法(用于撤销命令,可选)。 - 具体命令(Concrete Command)
实现命令接口,持有对接收者的引用,在execute()
中调用接收者的具体操作,完成命令的实际执行;undo()
则实现与execute()
相反的操作,用于撤销。 - 接收者(Receiver)
负责执行命令对应的具体业务逻辑,是命令的实际执行者(如开关、数据库等)。 - 调用者(Invoker)
持有命令对象,负责触发命令的执行(如按钮、遥控器等),不直接与接收者交互,仅依赖命令接口。
优点
- 解耦发送者与接收者
发送者(如智能开关)无需知道接收者(如灯光、空调)的具体实现,只需通过命令对象间接调用,降低了模块间的耦合度。 - 支持命令的扩展与组合
- 新增命令(如控制窗帘)只需实现
Command
接口,无需修改发送者或接收者(符合开闭原则)。 - 可通过组合多个命令形成"宏命令"(如"回家模式"= 开灯+开空调+拉窗帘)。
- 新增命令(如控制窗帘)只需实现
- 支持撤销与重做
通过记录命令历史,可实现undo()
(撤销)和redo()
(重做)功能,适用于需要回滚操作的场景(如文本编辑器、数据库事务)。 - 支持命令排队与日志
命令对象可被存储在队列中,实现延迟执行(如任务调度);也可记录日志,在系统崩溃后重新执行命令(如数据库恢复)。
适用场景
- 需要解耦请求发送者和接收者
- 如GUI按钮(发送者)与业务逻辑(接收者)的交互,按钮无需知道点击后具体执行什么操作
- 示例:文本编辑器的菜单按钮与编辑操作的分离
- 需要支持撤销(Undo)和重做(Redo)操作
- 如文本编辑器、图形设计软件、数据库事务等
- 通过记录命令历史,实现操作的回滚和重复执行
- 需要支持命令排队和延迟执行
- 如任务调度系统、批处理操作、线程池中的任务执行
- 命令可以被存储在队列中,按顺序或定时执行
- 需要支持宏命令(组合多个命令)
- 如"一键操作"(如"保存并退出"、"格式刷"功能)
- 将多个命令组合为一个命令,实现复杂操作的简化
- 需要记录命令日志或实现事务
- 如数据库的事务日志(记录所有操作,崩溃后重放恢复)
- 金融系统中的交易记录和审计跟踪
二、实现
以文档编辑器的示例,展示如何使用命令模式实现文本编辑、撤销和宏命令功能:
cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <stack>
// 接收者:文档编辑器
class DocumentEditor {
private:
std::string text_;
std::string clipboard_;
size_t cursorPosition_ = 0;
public:
// 获取当前文本
const std::string& getText() const { return text_; }
// 在光标位置插入文本
void insertText(const std::string& text) {
text_.insert(cursorPosition_, text);
cursorPosition_ += text.length();
std::cout << "插入文本: \"" << text << "\"\n";
}
// 删除指定长度的文本
std::string deleteText(size_t length) {
if (length > text_.length() - cursorPosition_) {
length = text_.length() - cursorPosition_;
}
std::string deleted = text_.substr(cursorPosition_, length);
text_.erase(cursorPosition_, length);
std::cout << "删除文本: \"" << deleted << "\"\n";
return deleted;
}
// 复制文本到剪贴板
void copyText(size_t start, size_t length) {
if (start + length > text_.length()) {
length = text_.length() - start;
}
clipboard_ = text_.substr(start, length);
std::cout << "复制文本: \"" << clipboard_ << "\"\n";
}
// 粘贴剪贴板内容
void pasteText() {
if (!clipboard_.empty()) {
insertText(clipboard_);
std::cout << "粘贴文本: \"" << clipboard_ << "\"\n";
}
}
// 设置光标位置
void setCursorPosition(size_t position) {
if (position <= text_.length()) {
cursorPosition_ = position;
std::cout << "光标位置设置为: " << position << "\n";
}
}
// 获取光标位置
size_t getCursorPosition() const { return cursorPosition_; }
// 显示当前文档状态
void display() const {
std::cout << "\n当前文档内容:\n" << text_ << "\n";
std::cout << "光标位置: " << cursorPosition_ << "\n\n";
}
};
// 命令接口
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0; // 执行命令
virtual void undo() = 0; // 撤销命令
virtual std::unique_ptr<Command> clone() const = 0; // 克隆命令(用于宏命令)
};
// 具体命令:插入文本
class InsertCommand : public Command {
private:
DocumentEditor& editor_;
std::string text_;
size_t cursorPos_; // 记录执行前的光标位置,用于撤销
public:
InsertCommand(DocumentEditor& editor, const std::string& text)
: editor_(editor), text_(text), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
editor_.insertText(text_);
}
void undo() override {
size_t currentPos = editor_.getCursorPosition();
editor_.setCursorPosition(cursorPos_);
editor_.deleteText(text_.length());
editor_.setCursorPosition(cursorPos_);
}
std::unique_ptr<Command> clone() const override {
return std::make_unique<InsertCommand>(*this);
}
};
// 具体命令:删除文本
class DeleteCommand : public Command {
private:
DocumentEditor& editor_;
size_t length_;
std::string deletedText_; // 记录删除的文本,用于撤销
size_t cursorPos_; // 记录执行前的光标位置
public:
DeleteCommand(DocumentEditor& editor, size_t length)
: editor_(editor), length_(length), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
deletedText_ = editor_.deleteText(length_);
}
void undo() override {
editor_.setCursorPosition(cursorPos_);
editor_.insertText(deletedText_);
}
std::unique_ptr<Command> clone() const override {
return std::make_unique<DeleteCommand>(*this);
}
};
// 具体命令:复制文本
class CopyCommand : public Command {
private:
DocumentEditor& editor_;
size_t start_;
size_t length_;
public:
CopyCommand(DocumentEditor& editor, size_t start, size_t length)
: editor_(editor), start_(start), length_(length) {}
void execute() override {
editor_.copyText(start_, length_);
}
// 复制操作没有状态变化,撤销不做任何事
void undo() override {
std::cout << "无法撤销复制操作\n";
}
std::unique_ptr<Command> clone() const override {
return std::make_unique<CopyCommand>(*this);
}
};
// 具体命令:粘贴文本
class PasteCommand : public Command {
private:
DocumentEditor& editor_;
size_t cursorPos_; // 记录执行前的光标位置
size_t pasteLength_ = 0; // 记录粘贴的长度,用于撤销
public:
explicit PasteCommand(DocumentEditor& editor)
: editor_(editor), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
size_t before = editor_.getText().length();
editor_.pasteText();
pasteLength_ = editor_.getText().length() - before;
}
void undo() override {
if (pasteLength_ > 0) {
editor_.setCursorPosition(cursorPos_);
editor_.deleteText(pasteLength_);
editor_.setCursorPosition(cursorPos_);
pasteLength_ = 0;
}
}
std::unique_ptr<Command> clone() const override {
return std::make_unique<PasteCommand>(*this);
}
};
// 宏命令:组合多个命令为一个命令
class MacroCommand : public Command {
private:
std::vector<std::unique_ptr<Command>> commands_;
public:
// 添加命令到宏
void addCommand(std::unique_ptr<Command> command) {
if (command) {
commands_.push_back(std::move(command));
}
}
// 执行所有命令
void execute() override {
std::cout << "\n执行宏命令开始...\n";
for (const auto& cmd : commands_) {
cmd->execute();
}
std::cout << "宏命令执行完毕\n";
}
// 撤销所有命令(逆序)
void undo() override {
std::cout << "\n撤销宏命令开始...\n";
for (auto it = commands_.rbegin(); it != commands_.rend(); ++it) {
(*it)->undo();
}
std::cout << "宏命令撤销完毕\n";
}
std::unique_ptr<Command> clone() const override {
auto macro = std::make_unique<MacroCommand>();
for (const auto& cmd : commands_) {
macro->addCommand(cmd->clone());
}
return macro;
}
};
// 调用者:命令管理器(处理命令执行和撤销)
class CommandManager {
private:
std::stack<std::unique_ptr<Command>> commandHistory_; // 命令历史栈
public:
// 执行命令并记录到历史
void executeCommand(std::unique_ptr<Command> command) {
if (command) {
command->execute();
commandHistory_.push(std::move(command));
}
}
// 撤销最后一个命令
void undoLastCommand() {
if (!commandHistory_.empty()) {
std::cout << "\n撤销操作...\n";
auto command = std::move(commandHistory_.top());
commandHistory_.pop();
command->undo();
} else {
std::cout << "\n没有可撤销的操作\n";
}
}
};
// 客户端代码
int main() {
// 创建接收者
DocumentEditor editor;
// 创建命令管理器
CommandManager cmdManager;
std::cout << "=== 初始状态 ===";
editor.display();
// 执行一系列命令
cmdManager.executeCommand(std::make_unique<InsertCommand>(editor, "Hello, "));
cmdManager.executeCommand(std::make_unique<InsertCommand>(editor, "World!"));
editor.display();
// 删除最后一个字符
editor.setCursorPosition(12);
cmdManager.executeCommand(std::make_unique<DeleteCommand>(editor, 1));
editor.display();
// 插入新文本
cmdManager.executeCommand(std::make_unique<InsertCommand>(editor, "C++!"));
editor.display();
// 复制文本
cmdManager.executeCommand(std::make_unique<CopyCommand>(editor, 0, 6));
// 移动光标并粘贴
editor.setCursorPosition(13);
cmdManager.executeCommand(std::make_unique<PasteCommand>(editor));
editor.display();
// 撤销操作
cmdManager.undoLastCommand(); // 撤销粘贴
editor.display();
cmdManager.undoLastCommand(); // 撤销删除
editor.display();
// 创建宏命令:保存文档的标准操作
auto saveMacro = std::make_unique<MacroCommand>();
saveMacro->addCommand(std::make_unique<InsertCommand>(editor, "\n[已保存]"));
saveMacro->addCommand(std::make_unique<CopyCommand>(editor, 0, editor.getText().length()));
// 执行宏命令
cmdManager.executeCommand(std::move(saveMacro));
editor.display();
// 撤销宏命令
cmdManager.undoLastCommand();
editor.display();
return 0;
}
输出结果
=== 初始状态 ===
当前文档内容:
光标位置: 0
插入文本: "Hello, "
插入文本: "World!"
当前文档内容:
Hello, World!
光标位置: 13
光标位置设置为: 12
删除文本: "d"
当前文档内容:
Hello, Worl!
光标位置: 12
插入文本: "C++!"
当前文档内容:
Hello, WorlC++!
光标位置: 16
复制文本: "Hello,"
光标位置设置为: 13
粘贴文本: "Hello,"
插入文本: "Hello,"
当前文档内容:
Hello, WorlC++!Hello,
光标位置: 20
撤销操作...
光标位置设置为: 13
删除文本: "Hello,"
光标位置设置为: 13
当前文档内容:
Hello, WorlC++!
光标位置: 13
撤销操作...
光标位置设置为: 12
插入文本: "d"
当前文档内容:
Hello, WorldC++!
光标位置: 13
执行宏命令开始...
插入文本: "\n[已保存]"
复制文本: "Hello, WorldC++!\n[已保存]"
宏命令执行完毕
当前文档内容:
Hello, WorldC++!
[已保存]
光标位置: 23
撤销操作...
撤销宏命令开始...
无法撤销复制操作
光标位置设置为: 13
删除文本: "\n[已保存]"
光标位置设置为: 13
宏命令撤销完毕
当前文档内容:
Hello, WorldC++!
光标位置: 13
应用场景
- 文本编辑器
- 实现撤销/重做、剪切/复制/粘贴等操作
- 每个编辑操作(如插入、删除)都封装为命令
- GUI框架
- 按钮、菜单等控件与背后的业务逻辑解耦
- 如Qt框架中的QAction类就是命令模式的实现
- 数据库事务
- 将一组操作封装为事务命令,支持提交和回滚
- 确保数据操作的原子性
- 遥控器和智能设备
- 遥控器按钮(发送者)与设备操作(接收者)解耦
- 支持记录操作历史和定时执行
- 游戏开发
- 记录玩家操作历史,支持游戏存档和回退
- 实现宏操作(如一键连招)
三、优化
优化点
- CRTP基类实现代码复用
- 使用奇异递归模板模式(CRTP)创建
Command
基类,减少代码冗余 - 提供默认的
clone()
实现,子类无需重复编写
- 使用奇异递归模板模式(CRTP)创建
- 完善的撤销与重做机制
- 引入双栈结构(撤销栈和重做栈),支持多级撤销和重做
- 新操作执行时自动清空重做栈,符合用户预期
- 命令日志系统
- 添加
CommandLogger
类,记录所有命令的执行和撤销操作 - 日志包含时间戳、文档名称和命令详情,便于调试和审计
- 添加
- 增强的类型安全与异常处理
- 使用智能指针
std::unique_ptr
管理命令生命周期,避免内存泄漏 - 增加边界检查和异常处理,提高代码健壮性
- 所有命令操作都有明确的前置条件检查
- 使用智能指针
- 宏命令的改进实现
- 宏命令支持命名和克隆,便于保存和重用
- 撤销宏命令时按逆序撤销所有子命令,保证状态一致性
- 文档状态管理
- 为文档添加名称标识,支持多文档场景
- 命令操作更精确地记录和恢复状态(如光标位置)
- 现代C++特性应用
- 使用
std::chrono
实现高精度时间戳 - 采用
std::stringstream
格式化输出 - 使用
override
关键字明确重写关系,提高代码可读性
- 使用
cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <stack>
#include <fstream>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <algorithm>
// 前向声明
class DocumentEditor;
// 命令接口 - 采用CRTP实现部分功能复用
template <typename Derived>
class Command {
public:
using Ptr = std::unique_ptr<Command>;
virtual ~Command() = default;
// 执行命令
virtual void execute() = 0;
// 撤销命令
virtual void undo() = 0;
// 获取命令描述(用于日志)
virtual std::string getDescription() const = 0;
// 克隆命令(用于宏命令和日志)
virtual Ptr clone() const {
return std::make_unique<Derived>(static_cast<const Derived&>(*this));
}
};
// 接收者:文档编辑器
class DocumentEditor {
private:
std::string text_;
std::string clipboard_;
size_t cursorPosition_ = 0;
std::string name_; // 文档名称
public:
explicit DocumentEditor(std::string name) : name_(std::move(name)) {}
// 获取当前文本
const std::string& getText() const { return text_; }
const std::string& getName() const { return name_; }
// 在光标位置插入文本
void insertText(const std::string& text) {
text_.insert(cursorPosition_, text);
cursorPosition_ += text.length();
}
// 删除指定长度的文本,返回被删除的内容
std::string deleteText(size_t length) {
if (length == 0) return "";
const size_t actualLength = std::min(length, text_.length() - cursorPosition_);
if (actualLength == 0) return "";
std::string deleted = text_.substr(cursorPosition_, actualLength);
text_.erase(cursorPosition_, actualLength);
return deleted;
}
// 复制文本到剪贴板
void copyText(size_t start, size_t length) {
if (start >= text_.length() || length == 0) {
clipboard_.clear();
return;
}
const size_t actualLength = std::min(length, text_.length() - start);
clipboard_ = text_.substr(start, actualLength);
}
// 粘贴剪贴板内容,返回粘贴的长度
size_t pasteText() {
if (clipboard_.empty()) return 0;
const size_t prevLength = text_.length();
insertText(clipboard_);
return text_.length() - prevLength;
}
// 设置光标位置
void setCursorPosition(size_t position) {
cursorPosition_ = std::min(position, text_.length());
}
// 获取光标位置
size_t getCursorPosition() const { return cursorPosition_; }
// 显示当前文档状态
void display() const {
std::cout << "\n文档 [" << name_ << "] 内容:\n"
<< text_ << "\n光标位置: " << cursorPosition_ << "\n";
}
};
// 具体命令:插入文本
class InsertCommand : public Command<InsertCommand> {
private:
DocumentEditor& editor_;
std::string text_;
size_t cursorPos_; // 执行前的光标位置
public:
InsertCommand(DocumentEditor& editor, std::string text)
: editor_(editor), text_(std::move(text)), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
editor_.insertText(text_);
}
void undo() override {
const size_t currentPos = editor_.getCursorPosition();
editor_.setCursorPosition(cursorPos_);
editor_.deleteText(text_.length());
editor_.setCursorPosition(cursorPos_);
}
std::string getDescription() const override {
return "插入文本: \"" + text_ + "\"";
}
};
// 具体命令:删除文本
class DeleteCommand : public Command<DeleteCommand> {
private:
DocumentEditor& editor_;
size_t length_;
std::string deletedText_; // 保存被删除的文本用于撤销
size_t cursorPos_; // 执行前的光标位置
public:
DeleteCommand(DocumentEditor& editor, size_t length)
: editor_(editor), length_(length), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
deletedText_ = editor_.deleteText(length_);
}
void undo() override {
if (!deletedText_.empty()) {
editor_.setCursorPosition(cursorPos_);
editor_.insertText(deletedText_);
}
}
std::string getDescription() const override {
return "删除文本: \"" + deletedText_ + "\"";
}
};
// 具体命令:复制文本
class CopyCommand : public Command<CopyCommand> {
private:
DocumentEditor& editor_;
size_t start_;
size_t length_;
std::string copiedText_; // 记录复制的内容用于日志
public:
CopyCommand(DocumentEditor& editor, size_t start, size_t length)
: editor_(editor), start_(start), length_(length) {}
void execute() override {
editor_.copyText(start_, length_);
// 重新获取实际复制的内容用于日志
std::string temp;
if (start_ < editor_.getText().length()) {
const size_t actualLength = std::min(length_, editor_.getText().length() - start_);
copiedText_ = editor_.getText().substr(start_, actualLength);
}
}
void undo() override {
// 复制操作不改变文档状态,无需撤销
}
std::string getDescription() const override {
return "复制文本: \"" + copiedText_ + "\"";
}
};
// 具体命令:粘贴文本
class PasteCommand : public Command<PasteCommand> {
private:
DocumentEditor& editor_;
size_t cursorPos_; // 执行前的光标位置
size_t pasteLength_ = 0;// 粘贴的长度用于撤销
public:
explicit PasteCommand(DocumentEditor& editor)
: editor_(editor), cursorPos_(editor.getCursorPosition()) {}
void execute() override {
pasteLength_ = editor_.pasteText();
}
void undo() override {
if (pasteLength_ > 0) {
editor_.setCursorPosition(cursorPos_);
editor_.deleteText(pasteLength_);
editor_.setCursorPosition(cursorPos_);
pasteLength_ = 0;
}
}
std::string getDescription() const override {
return "粘贴文本 (长度: " + std::to_string(pasteLength_) + ")";
}
};
// 宏命令:组合多个命令
class MacroCommand : public Command<MacroCommand> {
private:
std::vector<Command::Ptr> commands_;
std::string name_; // 宏命令名称
public:
explicit MacroCommand(std::string name) : name_(std::move(name)) {}
// 添加命令到宏
void addCommand(Command::Ptr command) {
if (command) {
commands_.push_back(std::move(command));
}
}
void execute() override {
for (const auto& cmd : commands_) {
cmd->execute();
}
}
void undo() override {
// 逆序撤销命令
for (auto it = commands_.rbegin(); it != commands_.rend(); ++it) {
(*it)->undo();
}
}
std::string getDescription() const override {
return "宏命令: " + name_ + " (包含 " + std::to_string(commands_.size()) + " 个子命令)";
}
// 重写克隆方法以正确复制所有子命令
Command::Ptr clone() const override {
auto clone = std::make_unique<MacroCommand>(name_);
for (const auto& cmd : commands_) {
clone->addCommand(cmd->clone());
}
return clone;
}
};
// 命令日志记录器
class CommandLogger {
private:
std::ofstream logFile_;
// 获取当前时间字符串
std::string getCurrentTime() const {
auto now = std::chrono::system_clock::now();
auto time = std::chrono::system_clock::to_time_t(now);
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch() % std::chrono::seconds(1)
);
std::stringstream ss;
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S")
<< "." << std::setw(3) << std::setfill('0') << ms.count();
return ss.str();
}
public:
explicit CommandLogger(const std::string& filename) {
logFile_.open(filename, std::ios::app);
if (logFile_.is_open()) {
logFile_ << "=== 命令日志开始: " << getCurrentTime() << " ===\n";
}
}
~CommandLogger() {
if (logFile_.is_open()) {
logFile_ << "=== 命令日志结束: " << getCurrentTime() << " ===\n\n";
logFile_.close();
}
}
// 记录命令执行
void logCommandExecution(const Command& cmd, const DocumentEditor& doc) {
if (logFile_.is_open()) {
logFile_ << "[" << getCurrentTime() << "] 文档: " << doc.getName()
<< " - 执行: " << cmd.getDescription() << "\n";
}
}
// 记录命令撤销
void logCommandUndo(const Command& cmd, const DocumentEditor& doc) {
if (logFile_.is_open()) {
logFile_ << "[" << getCurrentTime() << "] 文档: " << doc.getName()
<< " - 撤销: " << cmd.getDescription() << "\n";
}
}
};
// 命令管理器:支持撤销和重做
class CommandManager {
private:
std::stack<Command::Ptr> undoStack_; // 撤销栈
std::stack<Command::Ptr> redoStack_; // 重做栈
CommandLogger logger_; // 命令日志
DocumentEditor& editor_; // 关联的文档编辑器
public:
CommandManager(DocumentEditor& editor, const std::string& logFilename)
: logger_(logFilename), editor_(editor) {}
// 执行命令
void execute(Command::Ptr command) {
if (!command) return;
// 执行前清空重做栈(新操作会破坏重做可能性)
while (!redoStack_.empty()) redoStack_.pop();
// 执行命令并记录
command->execute();
logger_.logCommandExecution(*command, editor_);
undoStack_.push(std::move(command));
}
// 撤销最后一个命令
bool undo() {
if (undoStack_.empty()) return false;
auto command = std::move(undoStack_.top());
undoStack_.pop();
command->undo();
logger_.logCommandUndo(*command, editor_);
redoStack_.push(std::move(command));
return true;
}
// 重做最后一个被撤销的命令
bool redo() {
if (redoStack_.empty()) return false;
auto command = std::move(redoStack_.top());
redoStack_.pop();
command->execute();
logger_.logCommandExecution(*command, editor_);
undoStack_.push(std::move(command));
return true;
}
// 执行宏命令
void executeMacro(MacroCommand macro) {
// 克隆宏命令以便保存到历史记录
auto macroPtr = std::make_unique<MacroCommand>(std::move(macro));
execute(std::move(macroPtr));
}
};
// 客户端代码
int main() {
try {
// 创建文档编辑器
DocumentEditor editor("example.txt");
// 创建命令管理器(带日志)
CommandManager cmdManager(editor, "command_log.txt");
std::cout << "=== 初始状态 ===";
editor.display();
// 执行一系列编辑命令
cmdManager.execute(std::make_unique<InsertCommand>(editor, "设计模式 "));
cmdManager.execute(std::make_unique<InsertCommand>(editor, "之命令模式"));
std::cout << "\n=== 插入文本后 ===";
editor.display();
// 复制并粘贴文本
cmdManager.execute(std::make_unique<CopyCommand>(editor, 0, 4));
editor.setCursorPosition(editor.getText().length());
cmdManager.execute(std::make_unique<PasteCommand>(editor));
std::cout << "\n=== 复制粘贴后 ===";
editor.display();
// 删除多余内容
editor.setCursorPosition(4);
cmdManager.execute(std::make_unique<DeleteCommand>(editor, 3));
std::cout << "\n=== 删除文本后 ===";
editor.display();
// 撤销操作
if (cmdManager.undo()) {
std::cout << "\n=== 撤销删除后 ===";
editor.display();
}
// 重做操作
if (cmdManager.redo()) {
std::cout << "\n=== 重做删除后 ===";
editor.display();
}
// 创建并执行宏命令
MacroCommand saveMacro("保存文档");
saveMacro.addCommand(std::make_unique<InsertCommand>(editor, "\n[最后编辑于: 2024-08-23]"));
saveMacro.addCommand(std::make_unique<CopyCommand>(editor, 0, editor.getText().length()));
cmdManager.executeMacro(std::move(saveMacro));
std::cout << "\n=== 执行宏命令后 ===";
editor.display();
// 撤销宏命令
if (cmdManager.undo()) {
std::cout << "\n=== 撤销宏命令后 ===";
editor.display();
}
} catch (const std::exception& e) {
std::cerr << "错误: " << e.what() << std::endl;
return 1;
}
return 0;
}
优化后的优势
- 更完整的功能
- 新增重做功能,符合主流软件的操作习惯
- 命令日志支持审计和故障恢复,适合生产环境
- 更高的代码质量
- 强类型检查和边界验证减少运行时错误
- RAII资源管理(智能指针、日志文件)避免资源泄漏
- 更好的可扩展性
- 新增命令只需继承CRTP基类并实现核心方法
- 宏命令支持任意嵌套,可构建复杂操作序列
- 更贴近实际应用
- 支持多文档编辑场景
- 命令日志为系统提供可追溯性,满足企业级应用需求
- 更友好的用户体验
- 撤销/重做机制符合用户直觉
- 操作反馈更清晰,状态转换更平滑