Skip to content

备忘录模式 (Memento Pattern)

概述

备忘录模式是一种行为型设计模式,它允许在不破坏封装性的前提下捕获一个对象的内部状态,并在该对象之外保存这个状态,以便在需要时恢复到原先保存的状态。

备忘录模式的核心思想是通过创建一个备忘录对象来存储原发器(Originator)对象的内部状态,而备忘录对象只能由原发器对象创建和读取,其他对象只能保存和传递备忘录对象,不能修改其内容。这样可以保证对象状态的封装性和完整性。

核心要点

  • 状态保存:在不破坏封装性的前提下保存对象的内部状态
  • 可恢复性:允许对象恢复到之前保存的状态
  • 封装性:备忘录对象的内容只能由原发器访问和修改
  • 历史记录:可以保存对象的多个历史状态,支持多次撤销和重做

应用场景

  • 需要实现撤销/重做功能时:如文本编辑器、图形编辑软件等
  • 需要保存对象状态的快照时:如游戏存档、配置文件备份等
  • 需要防止对象外部直接访问和修改其内部状态时:保护对象的封装性
  • 需要实现状态历史记录和回溯功能时:如版本控制系统

结构

备忘录模式包含以下角色:

  1. 原发器(Originator):创建备忘录对象并记录其当前内部状态,也可以使用备忘录对象恢复内部状态
  2. 备忘录(Memento):存储原发器对象的内部状态,只允许原发器对象访问其状态
  3. 管理者(Caretaker):保存备忘录对象,但不能操作或检查备忘录对象的内容

实现示例

1. 基本备忘录模式实现

java
// 备忘录类
public class Memento {
    private String state; // 存储的状态
    private String date; // 创建日期
    
    // 私有构造函数,只允许Originator创建
    protected Memento(String state) {
        this.state = state;
        this.date = java.time.LocalDateTime.now().toString();
    }
    
    // 只允许Originator访问状态
    protected String getState() {
        return state;
    }
    
    // 获取创建日期(可选)
    public String getDate() {
        return date;
    }
    
    @Override
    public String toString() {
        return "备忘录[状态='" + state + "', 创建时间='" + date + "']";
    }
}

// 原发器类
public class Originator {
    private String state; // 内部状态
    
    // 设置状态
    public void setState(String state) {
        System.out.println("设置状态为: " + state);
        this.state = state;
    }
    
    // 获取状态
    public String getState() {
        return state;
    }
    
    // 创建备忘录对象,保存当前状态
    public Memento createMemento() {
        System.out.println("创建备忘录,保存当前状态");
        return new Memento(state);
    }
    
    // 从备忘录对象恢复状态
    public void restoreFromMemento(Memento memento) {
        if (memento != null) {
            this.state = memento.getState();
            System.out.println("从备忘录恢复状态为: " + state);
        }
    }
}

// 管理者类
public class Caretaker {
    private List<Memento> mementoList = new ArrayList<>(); // 保存备忘录列表
    private int currentIndex = -1; // 当前状态索引
    
    // 添加备忘录
    public void addMemento(Memento memento) {
        // 移除当前索引之后的所有备忘录(如果有)
        if (currentIndex < mementoList.size() - 1) {
            mementoList = new ArrayList<>(mementoList.subList(0, currentIndex + 1));
        }
        
        // 添加新备忘录
        mementoList.add(memento);
        currentIndex = mementoList.size() - 1;
        System.out.println("添加备忘录,当前索引: " + currentIndex);
    }
    
    // 获取上一个备忘录(撤销)
    public Memento undo() {
        if (currentIndex > 0) {
            currentIndex--;
            System.out.println("撤销操作,当前索引: " + currentIndex);
            return mementoList.get(currentIndex);
        } else {
            System.out.println("已经是最早的状态,无法撤销");
            return null;
        }
    }
    
    // 获取下一个备忘录(重做)
    public Memento redo() {
        if (currentIndex < mementoList.size() - 1) {
            currentIndex++;
            System.out.println("重做操作,当前索引: " + currentIndex);
            return mementoList.get(currentIndex);
        } else {
            System.out.println("已经是最新的状态,无法重做");
            return null;
        }
    }
    
    // 获取当前备忘录
    public Memento getCurrentMemento() {
        if (currentIndex >= 0 && currentIndex < mementoList.size()) {
            return mementoList.get(currentIndex);
        }
        return null;
    }
    
    // 获取备忘录历史
    public void printHistory() {
        System.out.println("\n=== 备忘录历史 ===");
        for (int i = 0; i < mementoList.size(); i++) {
            String marker = (i == currentIndex) ? "[当前] " : "       ";
            System.out.println(marker + "索引 " + i + ": " + mementoList.get(i));
        }
        System.out.println("==================\n");
    }
    
    // 获取备忘录数量
    public int getMementoCount() {
        return mementoList.size();
    }
}

// 客户端
public class MementoPatternDemo {
    public static void main(String[] args) {
        // 创建原发器和管理者
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        
        // 设置初始状态
        originator.setState("状态1");
        caretaker.addMemento(originator.createMemento()); // 保存状态1
        
        // 改变状态
        originator.setState("状态2");
        caretaker.addMemento(originator.createMemento()); // 保存状态2
        
        // 改变状态
        originator.setState("状态3");
        caretaker.addMemento(originator.createMemento()); // 保存状态3
        
        // 打印历史
        caretaker.printHistory();
        
        // 执行撤销操作
        System.out.println("执行撤销操作:");
        originator.restoreFromMemento(caretaker.undo()); // 恢复到状态2
        System.out.println("当前状态: " + originator.getState());
        
        // 再次执行撤销操作
        System.out.println("再次执行撤销操作:");
        originator.restoreFromMemento(caretaker.undo()); // 恢复到状态1
        System.out.println("当前状态: " + originator.getState());
        
        // 尝试再次撤销(应该失败)
        System.out.println("尝试再次撤销:");
        originator.restoreFromMemento(caretaker.undo());
        System.out.println("当前状态: " + originator.getState());
        
        // 执行重做操作
        System.out.println("执行重做操作:");
        originator.restoreFromMemento(caretaker.redo()); // 恢复到状态2
        System.out.println("当前状态: " + originator.getState());
        
        // 打印历史
        caretaker.printHistory();
        
        // 改变状态并保存(会清除重做历史)
        originator.setState("状态4");
        caretaker.addMemento(originator.createMemento()); // 保存状态4
        System.out.println("当前状态: " + originator.getState());
        
        // 打印历史
        caretaker.printHistory();
        
        // 尝试重做(应该失败,因为状态4是新保存的)
        System.out.println("尝试重做:");
        originator.restoreFromMemento(caretaker.redo());
    }
}

2. 复杂状态的备忘录实现

java
import java.io.*;
import java.util.*;

// 游戏角色状态类(复杂状态)
class GameCharacterState implements Serializable {
    private String name;
    private int health;
    private int mana;
    private int level;
    private Map<String, Integer> inventory; // 物品栏
    private String location;
    private Date saveTime;
    
    public GameCharacterState(String name, int health, int mana, int level, Map<String, Integer> inventory, String location) {
        this.name = name;
        this.health = health;
        this.mana = mana;
        this.level = level;
        this.inventory = new HashMap<>(inventory); // 深拷贝物品栏
        this.location = location;
        this.saveTime = new Date();
    }
    
    // getter方法
    public String getName() { return name; }
    public int getHealth() { return health; }
    public int getMana() { return mana; }
    public int getLevel() { return level; }
    public Map<String, Integer> getInventory() { return new HashMap<>(inventory); }
    public String getLocation() { return location; }
    public Date getSaveTime() { return saveTime; }
    
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("角色状态[\n");
        sb.append("  名称: ").append(name).append("\n");
        sb.append("  等级: ").append(level).append("\n");
        sb.append("  生命值: ").append(health).append("\n");
        sb.append("  魔法值: ").append(mana).append("\n");
        sb.append("  位置: ").append(location).append("\n");
        sb.append("  物品栏: ").append(inventory).append("\n");
        sb.append("  保存时间: ").append(saveTime).append("\n");
        sb.append("]");
        return sb.toString();
    }
}

// 游戏角色备忘录类
class GameMemento implements Serializable {
    private GameCharacterState state;
    private String saveName;
    
    protected GameMemento(GameCharacterState state, String saveName) {
        this.state = state;
        this.saveName = saveName;
    }
    
    protected GameCharacterState getState() {
        return state;
    }
    
    public String getSaveName() {
        return saveName;
    }
    
    @Override
    public String toString() {
        return "存档['" + saveName + "'] - " + state.getSaveTime();
    }
}

// 游戏角色类(原发器)
class GameCharacter {
    private String name;
    private int health;
    private int mana;
    private int level;
    private Map<String, Integer> inventory;
    private String location;
    
    public GameCharacter(String name) {
        this.name = name;
        this.health = 100;
        this.mana = 50;
        this.level = 1;
        this.inventory = new HashMap<>();
        this.location = "新手村";
        
        // 初始物品
        inventory.put("木剑", 1);
        inventory.put("皮甲", 1);
        inventory.put("治疗药水", 3);
    }
    
    // 升级
    public void levelUp() {
        level++;
        health = 100 + level * 10; // 生命值随等级增长
        mana = 50 + level * 5; // 魔法值随等级增长
        System.out.println(name + " 升级了!当前等级: " + level + ", 生命值: " + health + ", 魔法值: " + mana);
    }
    
    // 受伤
    public void takeDamage(int damage) {
        health = Math.max(0, health - damage);
        System.out.println(name + " 受到了 " + damage + " 点伤害!当前生命值: " + health);
    }
    
    // 使用魔法
    public void useMagic(int cost) {
        if (mana >= cost) {
            mana -= cost;
            System.out.println(name + " 使用了魔法,消耗了 " + cost + " 点魔法值!当前魔法值: " + mana);
        } else {
            System.out.println(name + " 魔法值不足!");
        }
    }
    
    // 获得物品
    public void gainItem(String itemName, int quantity) {
        inventory.put(itemName, inventory.getOrDefault(itemName, 0) + quantity);
        System.out.println(name + " 获得了 " + quantity + " 个 " + itemName + "!");
    }
    
    // 移动到新位置
    public void moveTo(String newLocation) {
        this.location = newLocation;
        System.out.println(name + " 移动到了 " + newLocation + "!");
    }
    
    // 创建备忘录
    public GameMemento save(String saveName) {
        System.out.println("保存游戏状态到存档: " + saveName);
        return new GameMemento(
            new GameCharacterState(name, health, mana, level, inventory, location),
            saveName
        );
    }
    
    // 从备忘录恢复
    public void load(GameMemento memento) {
        if (memento != null) {
            GameCharacterState state = memento.getState();
            this.name = state.getName();
            this.health = state.getHealth();
            this.mana = state.getMana();
            this.level = state.getLevel();
            this.inventory = state.getInventory();
            this.location = state.getLocation();
            System.out.println("从存档['" + memento.getSaveName() + "'] 加载游戏状态完成!");
        }
    }
    
    // 显示当前状态
    public void displayStatus() {
        System.out.println("\n=== " + name + " 的当前状态 ===");
        System.out.println("等级: " + level);
        System.out.println("生命值: " + health);
        System.out.println("魔法值: " + mana);
        System.out.println("位置: " + location);
        System.out.println("物品栏: " + inventory);
        System.out.println("==============================\n");
    }
}

// 游戏存档管理类(管理者)
class GameSaveManager {
    private Map<String, GameMemento> saves = new HashMap<>(); // 存储多个存档
    
    // 保存游戏
    public void saveGame(String saveName, GameMemento memento) {
        saves.put(saveName, memento);
        System.out.println("游戏已保存为: " + saveName);
    }
    
    // 加载游戏
    public GameMemento loadGame(String saveName) {
        GameMemento memento = saves.get(saveName);
        if (memento != null) {
            System.out.println("加载存档: " + saveName);
            return memento;
        } else {
            System.out.println("未找到存档: " + saveName);
            return null;
        }
    }
    
    // 删除存档
    public void deleteSave(String saveName) {
        if (saves.remove(saveName) != null) {
            System.out.println("存档已删除: " + saveName);
        } else {
            System.out.println("未找到存档: " + saveName);
        }
    }
    
    // 列出所有存档
    public void listSaves() {
        System.out.println("\n=== 可用存档列表 ===");
        if (saves.isEmpty()) {
            System.out.println("没有可用的存档");
        } else {
            saves.forEach((name, memento) -> {
                System.out.println("- " + memento);
            });
        }
        System.out.println("====================\n");
    }
    
    // 获取存档数量
    public int getSaveCount() {
        return saves.size();
    }
    
    // 序列化存档到文件
    public void saveToFile(String filename) throws IOException {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) {
            oos.writeObject(saves);
            System.out.println("所有存档已保存到文件: " + filename);
        }
    }
    
    // 从文件加载存档
    @SuppressWarnings("unchecked")
    public void loadFromFile(String filename) throws IOException, ClassNotFoundException {
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) {
            saves = (Map<String, GameMemento>) ois.readObject();
            System.out.println("从文件加载存档完成: " + filename);
        }
    }
}

// 客户端:游戏示例
public class GameDemo {
    public static void main(String[] args) {
        // 创建游戏角色和存档管理器
        GameCharacter hero = new GameCharacter("勇者");
        GameSaveManager saveManager = new GameSaveManager();
        
        // 显示初始状态
        hero.displayStatus();
        
        // 保存初始状态
        saveManager.saveGame("save1", hero.save("初始状态"));
        
        // 进行一些游戏操作
        hero.levelUp();
        hero.gainItem("铁剑", 1);
        hero.moveTo("森林");
        hero.takeDamage(30);
        
        // 显示当前状态
        hero.displayStatus();
        
        // 保存当前状态
        saveManager.saveGame("save2", hero.save("森林冒险"));
        
        // 继续游戏操作
        hero.levelUp();
        hero.useMagic(20);
        hero.gainItem("钻石", 5);
        hero.moveTo("城堡");
        
        // 显示当前状态
        hero.displayStatus();
        
        // 保存当前状态
        saveManager.saveGame("save3", hero.save("城堡探索"));
        
        // 列出所有存档
        saveManager.listSaves();
        
        // 从第一个存档加载
        System.out.println("\n--- 从第一个存档加载 ---");
        hero.load(saveManager.loadGame("save1"));
        hero.displayStatus();
        
        // 从第三个存档加载
        System.out.println("\n--- 从第三个存档加载 ---");
        hero.load(saveManager.loadGame("save3"));
        hero.displayStatus();
        
        // 删除第二个存档
        System.out.println("\n--- 删除第二个存档 ---");
        saveManager.deleteSave("save2");
        saveManager.listSaves();
    }
}

实际应用示例:文本编辑器的撤销/重做功能

下面是一个实际应用的例子,展示如何使用备忘录模式实现文本编辑器的撤销/重做功能:

java
import java.util.ArrayList;
import java.util.List;

// 文档状态类(备忘录中存储的状态)
class DocumentState {
    private String content; // 文档内容
    private int cursorPosition; // 光标位置
    private long timestamp; // 时间戳
    
    public DocumentState(String content, int cursorPosition) {
        this.content = content;
        this.cursorPosition = cursorPosition;
        this.timestamp = System.currentTimeMillis();
    }
    
    // getter方法
    public String getContent() { return content; }
    public int getCursorPosition() { return cursorPosition; }
    public long getTimestamp() { return timestamp; }
    
    @Override
    public String toString() {
        return "文档状态[内容长度=" + content.length() + ", 光标位置=" + cursorPosition + ", 时间戳=" + timestamp + "]";
    }
}

// 文档备忘录类
class DocumentMemento {
    private DocumentState state;
    private String actionDescription; // 操作描述
    
    protected DocumentMemento(DocumentState state, String actionDescription) {
        this.state = state;
        this.actionDescription = actionDescription;
    }
    
    protected DocumentState getState() {
        return state;
    }
    
    public String getActionDescription() {
        return actionDescription;
    }
    
    @Override
    public String toString() {
        return actionDescription + " - " + state;
    }
}

// 文档类(原发器)
class Document {
    private String content = ""; // 文档内容
    private int cursorPosition = 0; // 光标位置
    
    // 插入文本
    public void insertText(String text) {
        StringBuilder sb = new StringBuilder(content);
        sb.insert(cursorPosition, text);
        content = sb.toString();
        cursorPosition += text.length();
        System.out.println("插入文本: \"" + text + "\"");
        System.out.println("当前内容: \"" + content + "\"");
        System.out.println("光标位置: " + cursorPosition);
    }
    
    // 删除文本
    public void deleteText(int length) {
        if (length <= 0 || cursorPosition - length < 0) {
            System.out.println("无法删除文本,参数无效");
            return;
        }
        
        String deletedText = content.substring(cursorPosition - length, cursorPosition);
        StringBuilder sb = new StringBuilder(content);
        sb.delete(cursorPosition - length, cursorPosition);
        content = sb.toString();
        cursorPosition -= length;
        
        System.out.println("删除文本: \"" + deletedText + "\"");
        System.out.println("当前内容: \"" + content + "\"");
        System.out.println("光标位置: " + cursorPosition);
    }
    
    // 设置光标位置
    public void setCursorPosition(int position) {
        if (position >= 0 && position <= content.length()) {
            this.cursorPosition = position;
            System.out.println("光标位置设置为: " + position);
        } else {
            System.out.println("无效的光标位置: " + position);
        }
    }
    
    // 创建备忘录
    public DocumentMemento save(String actionDescription) {
        System.out.println("保存文档状态: " + actionDescription);
        return new DocumentMemento(new DocumentState(content, cursorPosition), actionDescription);
    }
    
    // 从备忘录恢复
    public void restore(DocumentMemento memento) {
        if (memento != null) {
            DocumentState state = memento.getState();
            this.content = state.getContent();
            this.cursorPosition = state.getCursorPosition();
            System.out.println("恢复文档状态: " + memento.getActionDescription());
            System.out.println("当前内容: \"" + content + "\"");
            System.out.println("光标位置: " + cursorPosition);
        }
    }
    
    // 显示当前状态
    public void display() {
        System.out.println("\n=== 文档当前状态 ===");
        System.out.println("内容: \"" + content + "\"");
        System.out.println("长度: " + content.length());
        System.out.println("光标位置: " + cursorPosition);
        // 显示光标位置指示器
        StringBuilder indicator = new StringBuilder();
        for (int i = 0; i < cursorPosition; i++) {
            indicator.append(" ");
        }
        indicator.append("^");
        System.out.println(indicator);
        System.out.println("====================\n");
    }
}

// 编辑器历史管理类(管理者)
class EditorHistory {
    private List<DocumentMemento> history = new ArrayList<>(); // 历史记录
    private int currentIndex = -1; // 当前索引
    private int maxHistorySize = 100; // 最大历史记录数量
    
    // 添加历史记录
    public void addHistory(DocumentMemento memento) {
        // 移除当前索引之后的所有历史记录
        if (currentIndex < history.size() - 1) {
            history = new ArrayList<>(history.subList(0, currentIndex + 1));
        }
        
        // 添加新的历史记录
        history.add(memento);
        currentIndex = history.size() - 1;
        
        // 如果历史记录数量超过最大值,移除最旧的记录
        if (history.size() > maxHistorySize) {
            history.remove(0);
            currentIndex--;
        }
        
        System.out.println("添加历史记录,当前索引: " + currentIndex);
    }
    
    // 撤销操作
    public DocumentMemento undo() {
        if (canUndo()) {
            currentIndex--;
            System.out.println("执行撤销操作,当前索引: " + currentIndex);
            return history.get(currentIndex);
        } else {
            System.out.println("无法撤销,已经是最早的状态");
            return null;
        }
    }
    
    // 重做操作
    public DocumentMemento redo() {
        if (canRedo()) {
            currentIndex++;
            System.out.println("执行重做操作,当前索引: " + currentIndex);
            return history.get(currentIndex);
        } else {
            System.out.println("无法重做,已经是最新的状态");
            return null;
        }
    }
    
    // 检查是否可以撤销
    public boolean canUndo() {
        return currentIndex > 0;
    }
    
    // 检查是否可以重做
    public boolean canRedo() {
        return currentIndex < history.size() - 1;
    }
    
    // 获取当前历史记录
    public DocumentMemento getCurrentState() {
        if (currentIndex >= 0 && currentIndex < history.size()) {
            return history.get(currentIndex);
        }
        return null;
    }
    
    // 显示历史记录
    public void showHistory() {
        System.out.println("\n=== 历史记录 ===");
        for (int i = 0; i < history.size(); i++) {
            String marker = (i == currentIndex) ? "[当前] " : "       ";
            System.out.println(marker + "索引 " + i + ": " + history.get(i));
        }
        System.out.println("撤销: " + canUndo() + ", 重做: " + canRedo());
        System.out.println("================\n");
    }
    
    // 获取历史记录数量
    public int getHistorySize() {
        return history.size();
    }
    
    // 清空历史记录
    public void clearHistory() {
        history.clear();
        currentIndex = -1;
        System.out.println("历史记录已清空");
    }
}

// 文本编辑器类(客户端使用)
class TextEditor {
    private Document document;
    private EditorHistory history;
    
    public TextEditor() {
        this.document = new Document();
        this.history = new EditorHistory();
        // 保存初始状态
        history.addHistory(document.save("初始状态"));
    }
    
    // 执行命令并保存历史
    public void executeCommand(String command, Object... params) {
        // 保存操作前的状态
        history.addHistory(document.save("操作前: " + command));
        
        // 执行命令
        switch (command) {
            case "insert":
                if (params.length > 0 && params[0] instanceof String) {
                    document.insertText((String) params[0]);
                }
                break;
            case "delete":
                if (params.length > 0 && params[0] instanceof Integer) {
                    document.deleteText((Integer) params[0]);
                }
                break;
            case "cursor":
                if (params.length > 0 && params[0] instanceof Integer) {
                    document.setCursorPosition((Integer) params[0]);
                }
                break;
            default:
                System.out.println("未知命令: " + command);
                break;
        }
    }
    
    // 撤销
    public void undo() {
        DocumentMemento memento = history.undo();
        if (memento != null) {
            document.restore(memento);
        }
    }
    
    // 重做
    public void redo() {
        DocumentMemento memento = history.redo();
        if (memento != null) {
            document.restore(memento);
        }
    }
    
    // 显示文档
    public void displayDocument() {
        document.display();
    }
    
    // 显示历史
    public void displayHistory() {
        history.showHistory();
    }
}

// 客户端:文本编辑器演示
public class TextEditorDemo {
    public static void main(String[] args) {
        // 创建文本编辑器
        TextEditor editor = new TextEditor();
        
        // 显示初始状态
        editor.displayDocument();
        
        // 执行一些编辑操作
        editor.executeCommand("insert", "Hello");
        editor.executeCommand("insert", " World");
        editor.displayDocument();
        
        editor.executeCommand("cursor", 5);
        editor.executeCommand("insert", ",");
        editor.displayDocument();
        
        editor.executeCommand("cursor", 13);
        editor.executeCommand("insert", "!");
        editor.displayDocument();
        
        // 显示历史
        editor.displayHistory();
        
        // 执行撤销操作
        System.out.println("\n--- 执行撤销操作 ---");
        editor.undo(); // 撤销插入感叹号
        editor.displayDocument();
        
        editor.undo(); // 撤销移动光标
        editor.displayDocument();
        
        // 显示历史
        editor.displayHistory();
        
        // 执行重做操作
        System.out.println("\n--- 执行重做操作 ---");
        editor.redo(); // 重做移动光标
        editor.displayDocument();
        
        editor.redo(); // 重做插入感叹号
        editor.displayDocument();
        
        // 执行删除操作
        System.out.println("\n--- 执行删除操作 ---");
        editor.executeCommand("cursor", 12);
        editor.executeCommand("delete", 6); // 删除"World"
        editor.displayDocument();
        
        // 显示历史
        editor.displayHistory();
        
        // 执行撤销删除
        System.out.println("\n--- 撤销删除操作 ---");
        editor.undo(); // 撤销删除操作
        editor.displayDocument();
        
        // 最终历史
        editor.displayHistory();
    }
}

优缺点

优点

  • 状态封装:备忘录对象封装了原发器的内部状态,保持了良好的封装性
  • 状态恢复:允许对象恢复到之前的状态,实现撤销/重做功能
  • 简化原发器:原发器不需要管理状态历史,只需要创建和使用备忘录对象
  • 状态隔离:备忘录对象的内容只能由原发器访问和修改,其他对象无法修改

缺点

  • 内存消耗:如果需要保存大量的历史状态,可能会占用较多的内存
  • 实现复杂:对于复杂对象的状态保存,实现起来可能比较复杂
  • 版本兼容性:如果对象的结构发生变化,之前保存的备忘录可能无法正常使用

与其他模式的关系

  • 备忘录模式与命令模式:都支持撤销操作,但命令模式关注的是操作的撤销,备忘录模式关注的是状态的恢复
  • 备忘录模式与原型模式:都涉及到对象状态的复制,但原型模式关注的是创建对象的副本,备忘录模式关注的是保存和恢复对象的状态
  • 备忘录模式与单例模式:在某些情况下,管理者可以设计为单例模式,以便全局访问历史状态

总结

备忘录模式是一种有用的行为型设计模式,它允许在不破坏封装性的前提下保存和恢复对象的内部状态。备忘录模式特别适用于需要实现撤销/重做功能、状态快照、历史记录等场景,如文本编辑器、图形编辑软件、游戏存档等。在使用备忘录模式时,需要注意管理备忘录对象的数量和内存消耗,避免因为保存过多的历史状态而导致性能问题。