备忘录模式

简介

备忘录模式(Memento Pattern)又叫作快照模式(Snapshot Pattern)或令牌模式(Token Pattern),指在不破坏封装的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态,属于行为型设计模式。

通用模板

  1. 创建备忘录角色:用于存储Originator(发起人角色)的内部状态,且可以防止Originator以外的对象进行访问。

    java 复制代码
    // 备忘录
    public class Memento {
        private String state;
    
        public Memento(String state) {
            this.state = state;
        }
    
        public String getState() {
            return this.state;
        }
    }
  2. 创建发起人角色:负责创建一个备忘录,记录自身需要保存的状态;具备状态回滚功能。

    java 复制代码
    // 发起人
    public class Originator {
        // 内部状态
        private String state;
    
        public String getState() {
            return this.state;
        }
    
        public void setState(String state) {
            this.state = state;
        }
    
        // 创建一个备忘录
        public Memento createMemento() {
            return new Memento(this.state);
        }
    
        // 从备忘录恢复
        public void restoreMemento(Memento memento) {
            this.state = memento.getState();
        }
    }
  3. 创建备忘录管理者角色:负责存储、提供管理Memento(备忘录),无法对Memento的内容进行操作和访问。

    java 复制代码
    // 备忘录管理者
    public class Caretaker {
        // 备忘录对象
        private Memento memento;
    
        public Memento getMemento() {
            return this.memento;
        }
    
        public void storeMemento(Memento memento) {
            this.memento = memento;
        }
    }

模板测试

  1. 测试代码

    java 复制代码
    public class Client {
        public static void main(String[] args) {
            // 创建一个发起人角色
            Originator originator = new Originator();
            // 创建一个备忘录管理员角色
            Caretaker caretaker = new Caretaker();
            // 设置初始状态
            originator.setState("状态A");
            System.out.println("初始状态:" + originator.getState());
    
            // 保存当前状态
            caretaker.storeMemento(originator.createMemento());
            // 更改状态
            originator.setState("状态B");
            System.out.println("更改后的状态:" + originator.getState());
    
            // 恢复到之前的状态
            originator.restoreMemento(caretaker.getMemento());
            System.out.println("恢复后的状态:" + originator.getState());
    
        }
    }
  2. 测试结果

    java 复制代码
    初始状态:状态A
    更改后的状态:状态B
    恢复后的状态:状态A

应用场景

对于程序员来说,可能天天都在使用备忘录模式,比如我们每天使用的Git、SVN都可以提供一种代码版本撤回的功能。还有一个比较贴切的现实场景就是游戏的存档功能,通过将游戏当前进度存储到本地文件系统或数据库中,使得下次继续游戏时,玩家可以从之前的位置继续进行。

备忘录模式主要适用于以下应用场景。

(1)需要保存历史快照的场景。

(2)希望在对象之外保存状态,且除了自己,其他类对象无法访问状态保存的具体内容。

优点

(1)简化发起人实体类(Originator)的职责,隔离状态存储与获取,实现了信息的封装,客户端无须关心状态的保存细节。

(2)提供状态回滚功能。

缺点

备忘录模式的缺点主要是消耗资源。如果需要保存的状态过多,则每一次保存都会消耗很多内存。

"生搬硬套"实战

场景描述

假设你在编写一个文本编辑器应用程序,用户在编辑文档时,希望能够随时保存当前编辑的状态,并在需要时恢复到之前保存的状态。这就需要用到备忘录模式来实现撤销功能。

代码开发
  1. 创建备忘录角色(这里指用来存储文档的状态的备忘录)

    java 复制代码
    // 定义一个备忘录类来存储文档的状态
    public class DocumentMemento {
        private String content;
    
        public DocumentMemento(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    }
  2. 创建发起人角色(这里指文档编辑器)

    java 复制代码
    // 发起人角色(Originator),也就是我们的文档编辑器,它负责创建备忘录并恢复状态
    public class DocumentEditor {
        private String content;
    
        public void setContent(String content) {
            this.content = content;
        }
    
        public String getContent() {
            return content;
        }
    
        // 创建备忘录
        public DocumentMemento createMemento() {
            return new DocumentMemento(content);
        }
    
        // 从备忘录恢复状态
        public void restoreFromMemento(DocumentMemento memento) {
            this.content = memento.getContent();
        }
    }
  3. 创建备忘录管理者角色(这里指存储文档备忘录的管理类)

    java 复制代码
    import java.util.ArrayList;
    import java.util.List;
    
    // 管理者角色(Caretaker),它用来存储备忘录对象
    public class DocumentCaretaker {
        private List<DocumentMemento> mementos = new ArrayList<>();
    
        public void addMemento(DocumentMemento memento) {
            mementos.add(memento);
        }
    
        public DocumentMemento getMemento(int index) {
            return mementos.get(index);
        }
    }

至此,我们就通过"生搬硬套"备忘录模式的模板设计出一套文档备忘录的案例,接下来我们进行测试:

  • 测试代码

    java 复制代码
    public class Test {
        public static void main(String[] args) {
            // 创建一个发起人角色
            DocumentEditor editor = new DocumentEditor();
            // 创建一个备忘录管理员角色
            DocumentCaretaker caretaker = new DocumentCaretaker();
    
            // 设置初始文档内容
            editor.setContent("Hello, ");
            System.out.println("初始文档内容: " + editor.getContent());
    
            // 保存当前状态
            caretaker.addMemento(editor.createMemento());
    
            // 更改文档内容
            editor.setContent(editor.getContent() + "World!");
            System.out.println("更改后文档内容: " + editor.getContent());
    
            // 恢复到之前的状态
            editor.restoreFromMemento(caretaker.getMemento(0));
            System.out.println("恢复后的文档内容: " + editor.getContent());
        }
    }
  • 测试结果

    java 复制代码
    初始文档内容: Hello, 
    更改后文档内容: Hello, World!
    恢复后的文档内容: Hello, 

总结

备忘录模式的本质是从发起人实体类(Originator)隔离存储功能,降低实体类的职责。同时由于存储信息(Memento)独立,且存储信息的实体交由管理类(Caretaker)管理,则可以通过为管理类扩展额外的功能对存储信息进行扩展操作(比如增加历史快照功能)。

相关推荐
zzzhpzhpzzz13 天前
设计模式——备忘录模式
设计模式·备忘录模式
2401_8566545116 天前
这TOP3免费录屏软件,助你轻松跃升视频制作小能手
编辑器·音视频·视频编解码·视频·备忘录模式
tuodianke19 天前
Windows电脑桌面如何弄个好用的提醒备忘录?
笔记·科技·职场发展·软件需求·备忘录模式
麦克·唐20 天前
命令模式和备忘录模式实现undo、redo(C++)
c++·命令模式·备忘录模式
jzpfbpx24 天前
[go] 备忘录模式
开发语言·golang·备忘录模式
刷帅耍帅1 个月前
设计模式-备忘录模式
设计模式·备忘录模式
java_heartLake1 个月前
设计模式之备忘录模式
java·设计模式·备忘录模式
John_ToDebug1 个月前
设计模式之备忘录模式
c++·设计模式·备忘录模式
林小果11 个月前
备忘录模式
java·开发语言·设计模式·备忘录模式