筹划模式之备忘录模式:对象状态的可逆时光机

打印 上一主题 下一主题

主题 1800|帖子 1800|积分 5400

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
弁言

备忘录模式(Memento Pattern)是一种行为型筹划模式,它允许在不破坏封装性的前提下捕获并外部化对象的内部状态,以便后续可以规复到该状态。这种模式就像为对象提供了一个"时光机",让我们能够回溯到先前的状态。本文将深入解析备忘录模式的原理、实现方式以及典型应用场景。

1. 备忘录模式的核心概念

1.1 什么是备忘录模式?

备忘录模式通过三个核心角色实现状态保存:


  • Originator(原发器):需要保存状态的对象
  • Memento(备忘录):存储原发器状态的不可变对象
  • Caretaker(管理者):负责保存和管理备忘录
1.2 典型应用场景



  • 打消/重做功能(如文本编辑器)
  • 游戏存档/读档
  • 事务回滚机制
  • 配置历史纪录

2. 备忘录模式的实现方式

2.1 基本布局实现

  1. // 备忘录接口(窄接口,对外隐藏细节)
  2. public interface Memento {
  3.     // 不暴露任何方法
  4. }
  5. // 原发器
  6. class TextEditor {
  7.     private String content;
  8.    
  9.     // 创建备忘录
  10.     public Memento save() {
  11.         return new TextMemento(content);
  12.     }
  13.    
  14.     // 恢复状态
  15.     public void restore(Memento memento) {
  16.         TextMemento tm = (TextMemento)memento;
  17.         this.content = tm.getSavedContent();
  18.     }
  19.    
  20.     // 内部备忘录实现
  21.     private static class TextMemento implements Memento {
  22.         private final String content;
  23.         
  24.         private TextMemento(String content) {
  25.             this.content = content;
  26.         }
  27.         
  28.         private String getSavedContent() {
  29.             return content;
  30.         }
  31.     }
  32. }
  33. // 管理者
  34. class History {
  35.     private Stack<Memento> stack = new Stack<>();
  36.    
  37.     public void push(Memento memento) {
  38.         stack.push(memento);
  39.     }
  40.    
  41.     public Memento pop() {
  42.         return stack.pop();
  43.     }
  44. }
复制代码
2.2 进阶实现本领


  • 增量备忘录:只保存变化的部分状态
  • 长期化备忘录:将状态保存到数据库/文件
  • 深拷贝实现:使用序列化实现深度状态保存

3. 备忘录模式的最佳实践

3.1 封装性掩护



  • 使用内部类实现备忘录
  • 为备忘录筹划窄接口
  • 限定管理者对备忘录内容的访问
3.2 性能优化



  • 大对象考虑使用增量保存
  • 设置历史纪录上限
  • 实现懒加载机制
3.3 与其他模式团结



  • 与下令模式实现可打消操作
  • 与原型模式实现状态克隆
  • 与观察者模式实现状态变更关照

4. 备忘录模式的实际应用

4.1 文档编辑器的打消功能

  1. // 完整实现示例
  2. class Document {
  3.     private StringBuilder content = new StringBuilder();
  4.     private History history = new History();
  5.    
  6.     public void write(String text) {
  7.         history.push(createMemento());
  8.         content.append(text);
  9.     }
  10.    
  11.     public void undo() {
  12.         if (history.hasStates()) {
  13.             restoreFromMemento(history.pop());
  14.         }
  15.     }
  16.    
  17.     private Memento createMemento() {
  18.         return new DocumentMemento(content.toString());
  19.     }
  20.    
  21.     private void restoreFromMemento(Memento memento) {
  22.         DocumentMemento dm = (DocumentMemento)memento;
  23.         content = new StringBuilder(dm.getState());
  24.     }
  25.    
  26.     private static class DocumentMemento implements Memento {
  27.         private final String state;
  28.         
  29.         private DocumentMemento(String state) {
  30.             this.state = state;
  31.         }
  32.         
  33.         private String getState() {
  34.             return state;
  35.         }
  36.     }
  37. }
  38. class History {
  39.     private Deque<Memento> states = new ArrayDeque<>();
  40.     private static final int MAX_HISTORY = 10;
  41.    
  42.     public void push(Memento state) {
  43.         if (states.size() == MAX_HISTORY) {
  44.             states.removeFirst();
  45.         }
  46.         states.push(state);
  47.     }
  48.    
  49.     public Memento pop() {
  50.         return states.pop();
  51.     }
  52.    
  53.     public boolean hasStates() {
  54.         return !states.isEmpty();
  55.     }
  56. }
复制代码
4.2 游戏角色状态存档

  1. class GameCharacter {
  2.     private int health;
  3.     private int level;
  4.     private Position position;
  5.    
  6.     public GameSave save() {
  7.         return new GameSave(health, level, position.clone());
  8.     }
  9.    
  10.     public void load(GameSave save) {
  11.         this.health = save.getHealth();
  12.         this.level = save.getLevel();
  13.         this.position = save.getPosition().clone();
  14.     }
  15.    
  16.     // 备忘录实现
  17.     public static class GameSave {
  18.         private final int health;
  19.         private final int level;
  20.         private final Position position;
  21.         
  22.         private GameSave(int health, int level, Position position) {
  23.             this.health = health;
  24.             this.level = level;
  25.             this.position = position;
  26.         }
  27.         
  28.         // getters...
  29.     }
  30. }
复制代码
4.3 表单数据主动保存

  1. class FormData {
  2.     private Map<String, Object> fields = new HashMap<>();
  3.     private SaveManager saveManager = new SaveManager();
  4.    
  5.     public void setField(String name, Object value) {
  6.         saveManager.save(this.createSnapshot());
  7.         fields.put(name, value);
  8.     }
  9.    
  10.     public void restorePrevious() {
  11.         FormSnapshot snapshot = saveManager.getLastSnapshot();
  12.         if (snapshot != null) {
  13.             this.fields = snapshot.getFields();
  14.         }
  15.     }
  16.    
  17.     private FormSnapshot createSnapshot() {
  18.         return new FormSnapshot(new HashMap<>(fields));
  19.     }
  20.    
  21.     private static class FormSnapshot {
  22.         private final Map<String, Object> fields;
  23.         
  24.         private FormSnapshot(Map<String, Object> fields) {
  25.             this.fields = fields;
  26.         }
  27.         
  28.         private Map<String, Object> getFields() {
  29.             return new HashMap<>(fields);
  30.         }
  31.     }
  32. }
复制代码
5. 备忘录模式的优缺点分析

5.1 优势



  • 完整状态保存:可以精确规复到任意历史状态
  • 封装掩护:不破坏原发器的封装性
  • 简化原发器代码:将状态管理职责分离
5.2 局限性



  • 内存斲丧:保存大量状态可能斲丧内存
  • 大对象性能题目:频仍保存大对象状态可能影响性能
  • 实现复杂度:需要合理筹划备忘录的存储布局

结语

备忘录模式为对象状态管理提供了优雅的解决方案,特别适合需要实现打消、历史纪录或事务回滚的场景。通过合理应用备忘录模式,可以增强系统的机动性和用户体验。在实际开发中,需要根据具体场景权衡内存使用和功能需求,须要时可团结其他模式进行优化。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表