Java设计模式之备忘录模式详解

Java设计模式之备忘录模式详解


一、备忘录模式核心思想

核心目标捕获对象内部状态并在需要时恢复,同时不破坏对象的封装性。如同游戏存档系统,允许玩家保存当前进度并在需要时回退到之前的状态。


二、备忘录模式类图(Mermaid)

创建 存储 Originator -state: String +saveToMemento() : Memento +restoreFromMemento(Memento) +setState(String) +getState() : String Memento -state: String +getState() : String +setState(String) Caretaker -mementos: List +addMemento(Memento) +getMemento(int) : Memento


三、代码实现示例

1. 文本编辑器撤销功能

java 复制代码
// 备忘录类(存储编辑器状态)
class TextMemento {
    private final String text;
    private final int cursorPosition;
    
    public TextMemento(String text, int cursorPosition) {
        this.text = text;
        this.cursorPosition = cursorPosition;
    }
    
    public String getText() {
        return text;
    }
    
    public int getCursorPosition() {
        return cursorPosition;
    }
}

// 原发器:文本编辑器
class TextEditor {
    private StringBuilder text = new StringBuilder();
    private int cursorPosition = 0;
    
    public void type(String words) {
        text.insert(cursorPosition, words);
        cursorPosition += words.length();
        System.out.println("当前文本: " + text);
    }
    
    public void moveCursor(int position) {
        cursorPosition = Math.max(0, Math.min(position, text.length()));
        System.out.println("光标移动到: " + cursorPosition);
    }
    
    public TextMemento save() {
        return new TextMemento(text.toString(), cursorPosition);
    }
    
    public void restore(TextMemento memento) {
        this.text = new StringBuilder(memento.getText());
        this.cursorPosition = memento.getCursorPosition();
        System.out.println("恢复文本: " + text);
    }
    
    public void printStatus() {
        System.out.println("文本: " + text);
        System.out.println("光标位置: " + cursorPosition);
    }
}

// 管理者:历史记录
class History {
    private List<TextMemento> states = new ArrayList<>();
    
    public void push(TextMemento state) {
        states.add(state);
    }
    
    public TextMemento pop() {
        if (states.isEmpty()) return null;
        return states.remove(states.size() - 1);
    }
    
    public TextMemento get(int index) {
        return states.get(index);
    }
}

// 客户端调用
public class Client {
    public static void main(String[] args) {
        TextEditor editor = new TextEditor();
        History history = new History();
        
        // 编辑文本
        editor.type("设计模式");
        history.push(editor.save());  // 保存状态1
        
        editor.type("备忘录");
        history.push(editor.save());  // 保存状态2
        
        editor.type("示例");
        System.out.println("\n当前状态:");
        editor.printStatus();
        
        // 撤销到上一步
        System.out.println("\n撤销操作:");
        editor.restore(history.pop());  // 恢复状态2
        editor.printStatus();
        
        // 再撤销一步
        System.out.println("\n再次撤销:");
        editor.restore(history.pop());  // 恢复状态1
        editor.printStatus();
    }
}

四、模式优缺点分析

✅ 优势

  • 状态封装:不暴露对象内部实现细节
  • 撤销/重做支持:轻松实现历史记录功能
  • 状态快照:支持任意时刻状态保存
  • 符合单一职责:状态管理职责分离

❌ 缺点

  • 内存消耗:大量状态保存可能导致内存占用高
  • 性能影响:大对象状态保存/恢复可能耗时
  • 复杂状态处理:嵌套对象状态保存较复杂

五、典型应用场景

  1. 文本编辑器:撤销/重做功能实现
  2. 游戏开发:保存/加载游戏进度
  3. 事务回滚:数据库操作回退
  4. 软件配置:保存和恢复用户设置
  5. 绘图软件:操作历史记录
  6. 状态机:回退到之前状态

六、Mermaid序列图(状态保存与恢复)

Client Originator Caretaker Memento 修改状态 saveToMemento() 创建备忘录(状态) 返回备忘录 addMemento(备忘录) getMemento() 备忘录 restoreFromMemento(备忘录) getState() 状态值 Client Originator Caretaker Memento


七、备忘录模式 vs 其他模式

对比模式 核心区别
命令模式 封装操作请求,可支持撤销
状态模式 对象行为随状态改变
原型模式 克隆对象而非保存状态

八、实际框架应用案例

1. Java Swing的UndoManager

管理 <<interface>> UndoableEdit +undo() +redo() AbstractUndoableEdit UndoManager CompoundEdit

2. Spring框架的事务管理

java 复制代码
@Transactional
public void transferMoney(Account from, Account to, double amount) {
    // 事务开始时创建备忘录(保存点)
    savepoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
    
    try {
        from.withdraw(amount);
        to.deposit(amount);
    } catch (Exception e) {
        // 回滚到保存点
        TransactionAspectSupport.currentTransactionStatus().rollbackToSavepoint(savepoint);
    }
}

九、高级应用技巧

1. 增量备忘录(节省内存)

java 复制代码
class IncrementalMemento {
    private final String diff;  // 只存储变化部分
    
    public IncrementalMemento(String diff) {
        this.diff = diff;
    }
    
    public String apply(String base) {
        // 应用差异到基础状态
        return base + diff;
    }
}

2. 多级撤销/重做栈

java 复制代码
class HistoryManager {
    private Stack<Memento> undoStack = new Stack<>();
    private Stack<Memento> redoStack = new Stack<>();
    
    public void save(Memento state) {
        undoStack.push(state);
        redoStack.clear();
    }
    
    public Memento undo() {
        if (!undoStack.isEmpty()) {
            Memento state = undoStack.pop();
            redoStack.push(state);
            return undoStack.isEmpty() ? null : undoStack.peek();
        }
        return null;
    }
    
    public Memento redo() {
        if (!redoStack.isEmpty()) {
            Memento state = redoStack.pop();
            undoStack.push(state);
            return state;
        }
        return null;
    }
}

十、常见问题解答

Q1:如何保存复杂对象状态?

  • 序列化 :实现Serializable接口
java 复制代码
class ComplexMemento implements Serializable {
    private Object complexState;
}

Q2:如何处理外部资源引用?

使用深拷贝避免外部资源影响:

java 复制代码
class ResourceMemento {
    private Resource resourceCopy;
    
    public ResourceMemento(Resource original) {
        this.resourceCopy = original.deepCopy();
    }
}

Q3:如何限制备忘录访问权限?

使用内部类实现封装:

java 复制代码
class Originator {
    private String state;
    
    // 内部备忘录类
    class Memento {
        private String state;
        
        private Memento(String state) {
            this.state = state;
        }
        
        private String getState() {
            return state;
        }
    }
    
    public Memento save() {
        return new Memento(state);
    }
}
相关推荐
我命由我123452 小时前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
武子康4 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
YuTaoShao7 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw7 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨7 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4048 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
Edingbrugh.南空8 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
QQ_4376643149 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
永卿0019 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式
使二颗心免于哀伤9 小时前
《设计模式之禅》笔记摘录 - 10.装饰模式
笔记·设计模式