一、模式定义
备忘录模式(Memento Pattern) 是一种行为设计模式,用于在不破坏对象封装性的前提下,捕获并保存对象的内部状态,以便后续恢复。核心思想是 状态快照管理,常用于实现撤销/重做、事务回滚等功能。
二、核心组件
| 组件 | 作用 | 
|---|---|
| Originator | 原始对象,产生状态快照 | 
| Memento | 备忘录对象,存储Originator的状态 | 
| Caretaker | 状态管理器,保存和管理备忘录历史 | 
三、模式优势
状态封装:不暴露对象内部实现细节
历史管理:支持多级撤销/重做操作
时间回溯:实现任意时间点的状态恢复
职责分离:状态存储与业务逻辑解耦
四、真实场景案例:文档版本控制系统
场景需求
开发IDE需要实现:
文档编辑时自动保存历史版本
支持最多50个历史版本的存储
允许用户自由切换文档版本
版本元数据记录(时间、作者)
五、Java实现代码
1. 备忘录接口(扩展元数据支持)
            
            
              java
              
              
            
          
          public interface DocumentMemento {
    String getVersionId();
    LocalDateTime getCreateTime();
    String getAuthor();
}
        2. 原发器(文档对象)
            
            
              java
              
              
            
          
          public class Document {
    private StringBuilder content = new StringBuilder();
    private String currentAuthor;
    
    public Document(String author) {
        this.currentAuthor = author;
    }
    // 编辑文档
    public void append(String text) {
        content.append(text);
    }
    // 创建快照
    public DocumentSnapshot createSnapshot() {
        return new DocumentSnapshot(
            UUID.randomUUID().toString(),
            LocalDateTime.now(),
            currentAuthor,
            content.toString()
        );
    }
    // 恢复快照
    public void restore(DocumentMemento memento) {
        if (memento instanceof DocumentSnapshot) {
            DocumentSnapshot snapshot = (DocumentSnapshot) memento;
            this.content = new StringBuilder(snapshot.getContent());
            this.currentAuthor = snapshot.getAuthor();
        }
    }
    // 内部备忘录实现
    private static class DocumentSnapshot implements DocumentMemento {
        private final String versionId;
        private final LocalDateTime createTime;
        private final String author;
        private final String content;
        public DocumentSnapshot(String versionId, LocalDateTime createTime, 
                               String author, String content) {
            this.versionId = versionId;
            this.createTime = createTime;
            this.author = author;
            this.content = content;
        }
        // Getters实现...
    }
}
        3. 负责人(版本控制器)
            
            
              java
              
              
            
          
          public class VersionController {
    private final Deque<DocumentMemento> history = new ArrayDeque<>();
    private final Deque<DocumentMemento> redoStack = new ArrayDeque<>();
    private static final int MAX_HISTORY = 50;
    public void saveVersion(DocumentMemento memento) {
        if (history.size() >= MAX_HISTORY) {
            history.removeFirst();
        }
        history.push(memento);
        redoStack.clear(); // 新操作后清空重做栈
    }
    public DocumentMemento undo() {
        if (!history.isEmpty()) {
            DocumentMemento current = history.pop();
            redoStack.push(current);
            return history.peekFirst(); // 返回前一个版本
        }
        return null;
    }
    public DocumentMemento redo() {
        if (!redoStack.isEmpty()) {
            DocumentMemento redo = redoStack.pop();
            history.push(redo);
            return redo;
        }
        return null;
    }
    public List<DocumentMemento> getVersionHistory() {
        return new ArrayList<>(history);
    }
}
        4. 客户端使用
            
            
              java
              
              
            
          
          public class IDEApplication {
    public static void main(String[] args) {
        // 初始化文档和版本控制器
        Document doc = new Document("DeveloperA");
        VersionController controller = new VersionController();
        // 首次保存
        doc.append("初始项目结构\n");
        controller.saveVersion(doc.createSnapshot());
        // 编辑并保存版本
        doc.append("添加用户模块\n");
        controller.saveVersion(doc.createSnapshot());
        
        doc.append("实现登录功能\n");
        controller.saveVersion(doc.createSnapshot());
        // 显示历史版本
        System.out.println("=== 版本历史 ===");
        controller.getVersionHistory().forEach(m -> 
            System.out.printf("[%s] %s - %s%n", 
                m.getVersionId().substring(0,8),
                m.getCreateTime().format(DateTimeFormatter.ISO_LOCAL_TIME),
                m.getAuthor())
        );
        // 执行撤销
        System.out.println("\n=== 执行撤销 ===");
        DocumentMemento undoVersion = controller.undo();
        doc.restore(undoVersion);
        System.out.println("当前内容:\n" + doc.getContent());
        // 执行重做
        System.out.println("\n=== 执行重做 ===");
        DocumentMemento redoVersion = controller.redo();
        doc.restore(redoVersion);
        System.out.println("当前内容:\n" + doc.getContent());
    }
}
        六、运行结果
            
            
              text
              
              
            
          
          === 版本历史 ===
[3b7f8a9c] 14:25:36.123 - DeveloperA
[2a6e5d8f] 14:25:35.987 - DeveloperA
[1c4d3b2a] 14:25:35.845 - DeveloperA
=== 执行撤销 ===
当前内容:
初始项目结构
添加用户模块
=== 执行重做 ===
当前内容:
初始项目结构
添加用户模块
实现登录功能
        七、模式变体与优化
1. 增量快照
            
            
              java
              
              
            
          
          // 差异存储优化
public class DeltaMemento implements DocumentMemento {
    private final String diff;  // 差异内容
    private final PatchType type; // 变更类型
    public enum PatchType { INSERT, DELETE, REPLACE }
}
        2. 加密快照
            
            
              java
              
              
            
          
          // 安全增强
public class SecureMemento implements DocumentMemento {
    private byte[] encryptedData;
    
    public SecureMemento(String content) {
        this.encryptedData = AESUtil.encrypt(content);
    }
    
    public String getDecryptedContent(String key) {
        return AESUtil.decrypt(encryptedData, key);
    }
}
        八、行业应用场景
| 场景 | 具体应用 | 优势体现 | 
|---|---|---|
| 图形编辑器 | 绘图步骤撤销/重做 | 支持复杂操作回溯 | 
| 游戏存档 | 玩家进度保存与加载 | 实现任意时刻存档恢复 | 
| 数据库事务 | 事务回滚机制 | 保证数据一致性 | 
| 配置管理系统 | 配置变更历史追踪 | 快速回滚错误配置 | 
| 浏览器历史记录 | 页面导航前进/后退 | 优化用户体验 | 
九、最佳实践建议
快照频率控制
            
            
              java
              
              
            
          
          // 自动保存策略
public enum SavePolicy {
    ON_CHANGE,  // 每次变更保存
    TIMED,      // 定时保存
    MANUAL      // 手动保存
}
        大对象处理
            
            
              java
              
              
            
          
          // 使用序列化存储快照
public class SerializedMemento implements Serializable {
    private byte[] serializedData;
    
    public SerializedMemento(Originator originator) throws IOException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(originator);
        this.serializedData = bos.toByteArray();
    }
}
        内存优化
            
            
              java
              
              
            
          
          // 软引用缓存
public class MemoryOptimizedCaretaker {
    private List<SoftReference<DocumentMemento>> history = new ArrayList<>();
}
        一句话总结
备忘录模式主要解决的是对象状态的保存和恢复问题,通过创建备忘录对象来存储和恢复对象的内部状态。