TypechoJoeTheme

至尊技术网

统计
登录
用户名
密码

C++备忘录模式:对象状态的时光回溯术

2025-07-29
/
0 评论
/
6 阅读
/
正在检测是否收录...
07/29


一、备忘录模式的核心价值

在软件开发中,我们常遇到这样的场景:用户点击了三次"撤销"按钮,系统需要回退到三个操作前的状态。传统做法可能是直接暴露对象内部状态进行修改——这就像为了给病人抽血而必须切开胸腔,显然违背了面向对象设计的封装原则

备忘录模式(Memento Pattern)通过引入"状态快照"的概念,在不破坏封装性的前提下,实现了对象状态的保存与恢复。其精妙之处在于:
- 原发器(Originator):拥有需要保存的状态
- 备忘录(Memento):存储原发器内部状态的快照
- 看管人(Caretaker):负责保存和管理备忘录,但不直接操作内容

二、C++实现的三重奏

1. 基础结构定义

cpp
// 备忘录类(状态容器)
class TextMemento {
friend class TextEditor; // 关键友元声明
std::string state_;
TextMemento(const std::string& s) : state_(s) {}
};

// 原发器(状态拥有者)
class TextEditor {
std::string content_;
public:
void type(const std::string& words) {
content_ += words;
}

TextMemento* save() const { 
    return new TextMemento(content_); 
}

void restore(const TextMemento* m) { 
    content_ = m->state_; 
}

void show() const { 
    std::cout << "Current: " << content_ << "\n"; 
}

};

// 看管人(历史记录管理器)
class HistoryKeeper {
std::stack<TextMemento> history_; public: ~HistoryKeeper() { while(!history_.empty()) { delete history_.top(); history_.pop(); } } void push(TextMemento m) { history.push(m); } TextMemento* pop() { if(history.empty()) return nullptr;
auto m = history.top(); history.pop();
return m;
}
};

2. 实现关键点解析

  • 友元类的妙用:备忘录通过friend授权原发器访问其私有成员,对外则保持完全封闭
  • 堆内存管理:采用裸指针需注意内存释放,实际项目中建议改用智能指针
  • 历史记录栈:使用std::stack实现先进后出的状态管理

3. 客户端使用示例

cpp
int main() {
TextEditor editor;
HistoryKeeper history;

editor.type("Hello");
history.push(editor.save());
editor.show();  // 输出: Current: Hello

editor.type(" World");
history.push(editor.save());
editor.show();  // 输出: Current: Hello World

editor.restore(history.pop());
editor.show();  // 回退到: Current: Hello

}

三、工程实践中的进阶技巧

1. 性能优化策略

  • 增量快照:对于大对象,仅存储变化部分而非完整状态
  • 序列化扩展:结合Protobuf或JSON实现磁盘持久化
    cpp // 原型扩展示例 class SerializeMemento : public TextMemento { public: std::string toJson() const { /*...*/ } static SerializeMemento* fromJson(const std::string&) { /*...*/ } };

2. 多状态管理

通过引入MementoCaretaker模板类,可以创建类型安全的通用管理器:
cpp template<typename T> class GenericHistory { std::vector<std::unique_ptr<T>> history_; // 实现undo/redo逻辑... };

3. 与命令模式结合

在复杂场景下,常将备忘录模式与命令模式联用:cpp
class ICommand {
public:
virtual void execute() = 0;
virtual void undo() = 0;
virtual ~ICommand() = default;
};

class TextCommand : public ICommand {
TextEditor& receiver_;
TextMemento* backup_;
public:
// 实现命令执行与撤销逻辑...
};

四、模式应用的现实思考

备忘录模式虽然优雅,但并非银弹。在以下场景需谨慎使用:
1. 高频状态变更:可能导致内存急剧增长
2. 简单状态对象:可能带来过度设计
3. 需要深度拷贝:复杂对象的复制成本较高

现代C++17后的改进方向:
- 使用std::optional处理可能为空的状态
- 通过移动语义优化状态传输效率
- 结合variant实现多类型状态存储

正如《设计模式:可复用面向对象软件的基础》所言:"模式的威力不在于代码复用,而在于经验复用。"备忘录模式教会我们的,不仅是技术实现,更是对对象边界的尊重——就像优秀的医生知道何时该使用微创手术,而非粗暴地打开患者的胸腔。

C++设计模式状态恢复备忘录模式Undo机制对象封装
朗读
赞(0)
版权属于:

至尊技术网

本文链接:

https://www.zzwws.cn/archives/34176/(转载时请注明本文出处及文章链接)

评论 (0)

人生倒计时

今日已经过去小时
这周已经过去
本月已经过去
今年已经过去个月

最新回复

  1. 强强强
    2025-04-07
  2. jesse
    2025-01-16
  3. sowxkkxwwk
    2024-11-20
  4. zpzscldkea
    2024-11-20
  5. bruvoaaiju
    2024-11-14

标签云