0131_备忘录模式(Memento)

备忘录模式(Memento)

意图

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后可以将该对象恢复到原先保存的状态。

UML 图

Memento

优点

  1. 封装性好:不暴露对象的实现细节,保持对象的封装性
  2. 状态恢复简单:可以轻松实现撤销/重做功能
  3. 状态管理集中:将状态保存和恢复的逻辑与业务逻辑分离
  4. 易于扩展:支持保存多个历史状态
  5. 符合单一职责:将状态保存的职责分离到单独的类中

缺点

  1. 资源消耗:如果需要保存大量状态或大对象,会消耗较多内存
  2. 性能开销:频繁创建和恢复备忘录可能影响性能
  3. 实现复杂度:需要维护备忘录的生命周期
  4. 可能暴露内部结构:如果设计不当,可能间接暴露对象的内部实现

代码示例

以人类状态管理系统为例:

1. 备忘录类 (Memento)

// 人类状态备忘录
public class HumanMemento {
    private final String name;
    private final int age;
    private final double weight;
    private final String healthStatus;
    private final List<String> memories;
    private final Date timestamp;
    
    public HumanMemento(String name, int age, double weight, 
                       String healthStatus, List<String> memories) {
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.healthStatus = healthStatus;
        this.memories = new ArrayList<>(memories); // 深拷贝
        this.timestamp = new Date();
    }
    
    // Getter方法
    public String getName() { return name; }
    public int getAge() { return age; }
    public double getWeight() { return weight; }
    public String getHealthStatus() { return healthStatus; }
    public List<String> getMemories() { return new ArrayList<>(memories); }
    public Date getTimestamp() { return timestamp; }
    
    @Override
    public String toString() {
        return String.format("状态快照[时间: %s, 姓名: %s, 年龄: %d, 体重: %.1fkg, 健康: %s]", 
                timestamp, name, age, weight, healthStatus);
    }
}

2. 原发器类 (Originator)

// 人类 - 原发器
public class Human {
    private String name;
    private int age;
    private double weight;
    private String healthStatus;
    private List<String> memories;
    
    public Human(String name, int age, double weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.healthStatus = "健康";
        this.memories = new ArrayList<>();
        addMemory("出生");
    }
    
    // 创建备忘录
    public HumanMemento createMemento() {
        return new HumanMemento(name, age, weight, healthStatus, memories);
    }
    
    // 从备忘录恢复
    public void restoreFromMemento(HumanMemento memento) {
        this.name = memento.getName();
        this.age = memento.getAge();
        this.weight = memento.getWeight();
        this.healthStatus = memento.getHealthStatus();
        this.memories = memento.getMemories();
    }
    
    // 业务方法
    public void growOlder() {
        age++;
        weight += 0.5;
        addMemory("过生日,现在" + age + "岁了");
    }
    
    public void exercise() {
        weight -= 1.0;
        healthStatus = "非常健康";
        addMemory("锻炼身体");
    }
    
    public void getSick() {
        healthStatus = "生病";
        weight -= 0.5;
        addMemory("生病了");
    }
    
    public void recover() {
        healthStatus = "康复中";
        addMemory("逐渐康复");
    }
    
    public void addMemory(String memory) {
        memories.add(memory + " - " + new Date());
    }
    
    public void displayStatus() {
        System.out.println("=== 当前状态 ===");
        System.out.println("姓名: " + name);
        System.out.println("年龄: " + age + "岁");
        System.out.println("体重: " + weight + "kg");
        System.out.println("健康状况: " + healthStatus);
        System.out.println("最近记忆: " + 
            (memories.isEmpty() ? "无" : memories.get(memories.size() - 1)));
        System.out.println("总记忆数量: " + memories.size());
        System.out.println("================\n");
    }
    
    // Getter方法
    public String getName() { return name; }
    public int getAge() { return age; }
    public double getWeight() { return weight; }
    public String getHealthStatus() { return healthStatus; }
    public List<String> getMemories() { return new ArrayList<>(memories); }
}

3. 负责人类 (Caretaker)

// 状态管理器 - 负责人
public class HumanStateManager {
    private final List<HumanMemento> mementos = new ArrayList<>();
    private final Human human;
    
    public HumanStateManager(Human human) {
        this.human = human;
    }
    
    // 保存状态
    public void saveState() {
        HumanMemento memento = human.createMemento();
        mementos.add(memento);
        System.out.println("✅ 已保存状态: " + memento);
    }
    
    // 恢复到指定状态
    public void restoreState(int index) {
        if (index < 0 || index >= mementos.size()) {
            System.out.println("❌ 无效的状态索引");
            return;
        }
        
        HumanMemento memento = mementos.get(index);
        human.restoreFromMemento(memento);
        System.out.println("↩️  已恢复到状态: " + memento);
    }
    
    // 撤销到上一个状态
    public void undo() {
        if (mementos.size() < 2) {
            System.out.println("❌ 没有足够的历史状态可撤销");
            return;
        }
        
        HumanMemento memento = mementos.get(mementos.size() - 2);
        human.restoreFromMemento(memento);
        mementos.remove(mementos.size() - 1); // 移除当前状态
        System.out.println("↩️  已撤销到状态: " + memento);
    }
    
    // 显示所有保存的状态
    public void showHistory() {
        System.out.println("=== 状态历史记录 ===");
        if (mementos.isEmpty()) {
            System.out.println("暂无历史记录");
        } else {
            for (int i = 0; i < mementos.size(); i++) {
                System.out.println(i + ": " + mementos.get(i));
            }
        }
        System.out.println("===================\n");
    }
    
    public int getHistorySize() {
        return mementos.size();
    }
}

4. 客户端代码

public class MementoPatternDemo {
    public static void main(String[] args) {
        System.out.println("=== 备忘录模式演示 - 人类状态管理系统 ===\n");
        
        // 创建人类对象
        Human person = new Human("张三", 20, 65.0);
        HumanStateManager manager = new HumanStateManager(person);
        
        // 初始状态
        System.out.println("初始状态:");
        person.displayStatus();
        manager.saveState();
        
        // 模拟人生变化
        System.out.println("一年后...");
        person.growOlder();
        person.exercise();
        person.displayStatus();
        manager.saveState();
        
        System.out.println("又过了一年...");
        person.growOlder();
        person.getSick();
        person.displayStatus();
        manager.saveState();
        
        System.out.println("康复期...");
        person.recover();
        person.addMemory("去医院检查");
        person.displayStatus();
        manager.saveState();
        
        // 显示历史记录
        manager.showHistory();
        
        // 测试撤销功能
        System.out.println("测试撤销功能:");
        manager.undo();
        person.displayStatus();
        
        // 恢复到特定状态
        System.out.println("恢复到第1个保存的状态:");
        manager.restoreState(1);
        person.displayStatus();
        
        // 继续添加新状态
        System.out.println("添加新经历...");
        person.addMemory("学习新技能");
        person.exercise();
        person.displayStatus();
        manager.saveState();
        
        // 最终历史记录
        manager.showHistory();
        
        System.out.println("=== 演示完成 ===");
    }
}

在Spring的应用

在Spring框架中,备忘录模式的应用体现在:

  1. HTTP Session管理:Spring Session可以保存和恢复用户的会话状态
  2. 事务管理:Spring的事务管理器在事务回滚时使用类似备忘录的模式恢复数据状态
  3. 表单处理:Spring MVC的表单标签库可以保存和恢复表单状态
  4. 缓存机制:Spring Cache可以保存方法调用结果,并在需要时恢复
  5. 状态机:Spring State Machine使用备忘录模式管理状态历史

总结

备忘录模式通过将对象状态外部化,实现了状态保存和恢复的功能,同时保持了对象的封装性。在人类状态管理系统的示例中,我们可以看到:

  1. Human类作为原发器,负责创建和恢复备忘录
  2. HumanMemento类封装了人类的状态信息,提供了状态的快照
  3. HumanStateManager类作为负责人,管理备忘录的存储和检索

这种模式特别适用于需要实现撤销/重做功能、状态历史记录或系统快照的场景。通过备忘录模式,我们可以轻松地回溯到对象的任意历史状态,为复杂的业务流程提供了强大的状态管理能力。

posted @ 2025-09-18 07:45  庞去广  阅读(22)  评论(0)    收藏  举报