• 设计模式-备忘录模式(Memento)


    一、备忘录模式概述

    1.1 什么是备忘录模式

    备忘录模式(Memento Pattern)是一种行为型设计模式,它允许你捕获对象的内部状态,并在需要时恢复该状态,而无需暴露该对象的实现细节。所谓备忘录模式就是在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样,以后就可以将该对象恢复到原先保存的状态。

    这种模式的名字可能对一些人来说稍微有点陌生,但其另一个名字快照模式可能会让人觉得更为熟悉。备忘录模式的适用场景包括:需要保存和恢复数据的场景,例如,编辑文档时需要撤销操作;需要避免重复计算的场景,例如,斐波那契数列;以及需要将一个对象的状态作为参数传递给其他对象的场景,例如,从数据库中查询数据。

    1.2 简单实现备忘录模式

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

    下面是一个简单的Java实现备忘录模式的例子:

    首先,我们创建一个原始类(Originator):

    public class Originator {
        private String state;
    
        public void setState(String state) {
            this.state = state;
        }
    
        public String getState() {
            return state;
        }
    
        public Memento saveStateToMemento() {
            return new Memento(state);
        }
    
        public void getStateFromMemento(Memento memento) {
            state = memento.getState();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    然后,我们创建一个备忘录类(Memento):

    public class Memento {
        private String state;
    
        public Memento(String state) {
            this.state = state;
        }
    
        public String getState() {
            return state;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    接下来,我们创建一个负责管理备忘录的类(Caretaker):

    import java.util.ArrayList;
    import java.util.List;
    
    public class Caretaker {
        private List<Memento> mementoList = new ArrayList<>();
    
        public void add(Memento state) {
            mementoList.add(state);
        }
    
        public Memento get(int index) {
            return mementoList.get(index);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    最后,我们在主函数中测试备忘录模式:

    public class Main {
        public static void main(String[] args) {
            Originator originator = new Originator();
            Caretaker caretaker = new Caretaker();
    
            originator.setState("状态1");
            caretaker.add(originator.saveStateToMemento());
    
            originator.setState("状态2");
            caretaker.add(originator.saveStateToMemento());
    
            originator.setState("状态3");
            caretaker.add(originator.saveStateToMemento());
    
            System.out.println("当前状态: " + originator.getState());
            originator.getStateFromMemento(caretaker.get(0));
            System.out.println("恢复后的状态: " + originator.getState());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    运行结果:

    当前状态: 状态3
    恢复后的状态: 状态1
    
    • 1
    • 2

    1.3 使用备忘录模式的注意事项

    • 1、备忘录的保存和使用必须在同一个上下文中,不能将备忘录传递给其他对象。如果需要传递备忘录,可以使用Caretaker类来管理备忘录。

    • 2、备忘录对象需要保存原始对象的内部状态,因此备忘录对象应该与原始对象具有相同的属性和方法。但是,备忘录对象不应该包含任何业务逻辑或行为。

    • 3、如果原始对象的内部状态被修改,备忘录对象也需要相应地更新。因此,在保存备忘录之前,需要先调用原始对象的saveStateToMemento()方法。

    • 4、如果需要恢复原始对象的内部状态,可以使用getStateFromMemento()方法。但是,需要注意的是,恢复后的状态可能不是最新的状态,因为原始对象可能在恢复状态之后又进行了修改。

    • 5、备忘录模式适用于那些需要保存和恢复状态的场景,但不适用于所有场景。如果只需要保存和恢复单个状态,可以使用简单变量来实现;如果需要保存和恢复多个状态,可以使用数据结构(如数组或列表)来管理备忘录对象。

    二、备忘录模式的用途

    • 1、备忘录模式主要用于保存和恢复对象的状态,以便在需要时可以恢复到先前的状态。这种模式通常用于以下情况:

    • 2、撤销操作:当一个操作序列可以被撤销时,可以使用备忘录模式来保存每个操作的结果,以便在需要时进行撤销。

    • 3、跨层传递参数:当一个对象需要将其状态传递给另一个对象时,可以使用备忘录模式将该对象的状态保存在一个备忘录中,然后将备忘录传递给另一个对象。

    • 4、避免重复计算:当一个对象的计算成本很高时,可以使用备忘录模式来保存其中间结果,以便在需要时可以直接使用这些结果,而不必重新计算它们。

    • 5、测试和维护:当需要对一个对象进行单元测试或维护时,可以使用备忘录模式来保存其当前状态,以便在测试或维护完成后可以恢复到先前的状态。

    三、备忘录模式实现方式

    3.1 基于数组的备忘录实现方式

    基于数组的备忘录实现方式可以通过以下步骤完成:

    创建一个类,该类包含一个用于保存状态的数组。
    在类中定义一个方法,该方法将对象的状态保存到数组中。
    在类中定义另一个方法,该方法从数组中恢复对象的状态。
    在需要保存和恢复状态的地方调用相应的方法。
    以下是一个简单的示例代码:

    public class Memento {
        private int[] state;
    
        public Memento(int[] state) {
            this.state = state;
        }
    
        public int[] getState() {
            return state;
        }
    }
    
    public class Originator {
        private int[] state;
    
        public void setState(int[] state) {
            this.state = state;
        }
    
        public int[] getState() {
            return state;
        }
    
        public Memento saveStateToMemento() {
            return new Memento(state);
        }
    
        public void getStateFromMemento(Memento memento) {
            state = memento.getState();
        }
    }
    
    public class Caretaker {
        private List<Memento> mementos = new ArrayList<>();
    
        public void add(Memento state) {
            mementos.add(state);
        }
    
        public Memento get(int index) {
            return mementos.get(index);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Originator originator = new Originator();
            Caretaker caretaker = new Caretaker();
    
            originator.setState(new int[]{1, 2, 3});
            caretaker.add(originator.saveStateToMemento());
    
            originator.setState(new int[]{4, 5, 6});
            caretaker.add(originator.saveStateToMemento());
    
            originator.getStateFromMemento(caretaker.get(0)); // 恢复到第一个状态
            System.out.println(Arrays.toString(originator.getState())); // 输出 [1, 2, 3]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    在这个示例中,我们创建了一个Originator类来表示原始对象,一个Memento类来表示备忘录,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。

    3.2 基于集合的备忘录实现方式

    基于集合的备忘录实现方式可以通过以下步骤完成:

    创建一个类,该类包含一个用于保存状态的集合。
    在类中定义一个方法,该方法将对象的状态添加到集合中。
    在类中定义另一个方法,该方法从集合中恢复对象的状态。
    在需要保存和恢复状态的地方调用相应的方法。
    以下是一个简单的示例代码:

    import java.util.ArrayList;
    import java.util.List;
    
    public class Memento {
        private List<String> state;
    
        public Memento() {
            state = new ArrayList<>();
        }
    
        public void addState(String state) {
            this.state.add(state);
        }
    
        public String getState(int index) {
            return state.get(index);
        }
    }
    
    public class Originator {
        private List<String> states;
    
        public Originator() {
            states = new ArrayList<>();
        }
    
        public void setState(String state) {
            states.add(state);
        }
    
        public String getState() {
            return states.get(states.size() - 1);
        }
    
        public Memento saveStateToMemento() {
            Memento memento = new Memento();
            memento.addState(getState());
            return memento;
        }
    
        public void getStateFromMemento(Memento memento) {
            int index = states.size() - 1;
            setState(memento.getState(index));
        }
    }
    
    public class Caretaker {
        private List<Memento> mementos;
    
        public Caretaker() {
            mementos = new ArrayList<>();
        }
    
        public void add(Memento memento) {
            mementos.add(memento);
        }
    
        public Memento get(int index) {
            return mementos.get(index);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Originator originator = new Originator();
            Caretaker caretaker = new Caretaker();
    
            originator.setState("状态1");
            caretaker.add(originator.saveStateToMemento());
    
            originator.setState("状态2");
            caretaker.add(originator.saveStateToMemento());
    
            originator.getStateFromMemento(caretaker.get(0)); // 恢复到第一个状态
            System.out.println(originator.getState()); // 输出 "状态1"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77

    在这个示例中,我们创建了一个Memento类来表示备忘录,一个Originator类来表示原始对象,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。

    3.3 基于HashMap的备忘录实现方式

    基于HashMap的备忘录实现方式可以通过以下步骤完成:

    创建一个类,该类包含一个用于保存状态的HashMap。
    在类中定义一个方法,该方法将对象的状态添加到HashMap中。
    在类中定义另一个方法,该方法从HashMap中恢复对象的状态。
    在需要保存和恢复状态的地方调用相应的方法。
    以下是一个简单的示例代码:

    import java.util.HashMap;
    
    public class Memento {
        private HashMap<String, Object> stateMap;
    
        public Memento() {
            stateMap = new HashMap<>();
        }
    
        public void addState(String key, Object value) {
            stateMap.put(key, value);
        }
    
        public Object getState(String key) {
            return stateMap.get(key);
        }
    }
    
    public class Originator {
        private String state;
    
        public void setState(String state) {
            this.state = state;
        }
    
        public String getState() {
            return state;
        }
    
        public Memento saveStateToMemento() {
            Memento memento = new Memento();
            memento.addState("state", state);
            return memento;
        }
    
        public void getStateFromMemento(Memento memento) {
            state = (String) memento.getState("state");
        }
    }
    
    public class Caretaker {
        private ArrayList<Memento> mementoList;
    
        public Caretaker() {
            mementoList = new ArrayList<>();
        }
    
        public void addMemento(Memento memento) {
            mementoList.add(memento);
        }
    
        public Memento getMemento(int index) {
            return mementoList.get(index);
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Originator originator = new Originator();
            Caretaker caretaker = new Caretaker();
    
            originator.setState("状态1");
            caretaker.addMemento(originator.saveStateToMemento());
    
            originator.setState("状态2");
            caretaker.addMemento(originator.saveStateToMemento());
    
            originator.setState((String) caretaker.getMemento(0).getState("state"));
            System.out.println("恢复后的状态: " + originator.getState()); // 输出 "恢复后的状态: 状态1"
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    在这个示例中,我们创建了一个Memento类来表示备忘录,一个Originator类来表示原始对象,一个Caretaker类来管理备忘录。在Main类的main方法中,我们创建了Originator和Caretaker对象,并使用它们来保存和恢复对象的状态。

    3.4 基于序列化的备忘录实现方式

    基于序列化的备忘录实现方式可以通过以下步骤完成:

    创建一个类,该类包含一个用于保存状态的私有成员变量。
    为该类添加一个构造函数,用于初始化私有成员变量。
    为该类添加一个序列化方法,用于将对象的状态保存到文件中。
    为该类添加一个反序列化方法,用于从文件中恢复对象的状态。
    在需要保存和恢复状态的地方调用相应的序列化和反序列化方法。
    以下是一个简单的示例代码:

    import java.io.*;
    
    class Memento implements Serializable {
        private String state;
    
        public Memento(String state) {
            this.state = state;
        }
    
        public String getState() {
            return state;
        }
    
        public void setState(String state) {
            this.state = state;
        }
    
        public void saveToFile(String fileName) {
            try {
                FileOutputStream fos = new FileOutputStream(fileName);
                ObjectOutputStream oos = new ObjectOutputStream(fos);
                oos.writeObject(this);
                oos.close();
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        public static Memento restoreFromFile(String fileName) {
            Memento memento = null;
            try {
                FileInputStream fis = new FileInputStream(fileName);
                ObjectInputStream ois = new ObjectInputStream(fis);
                memento = (Memento) ois.readObject();
                ois.close();
                fis.close();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
            return memento;
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Memento memento = new Memento("初始状态");
            System.out.println("当前状态: " + memento.getState());
    
            memento.setState("修改后的状态");
            System.out.println("修改后的状态: " + memento.getState());
    
            memento.saveToFile("memento.ser");
    
            Memento restoredMemento = Memento.restoreFromFile("memento.ser");
            System.out.println("恢复后的状态: " + restoredMemento.getState());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    在这个示例中,我们创建了一个名为Memento的类,它实现了Serializable接口。我们为这个类添加了一个私有成员变量state,以及一个构造函数、一个获取状态的方法、一个设置状态的方法、一个保存状态到文件的方法和一个从文件恢复状态的方法。在main方法中,我们创建了一个Memento对象,修改了它的状态,然后将它的状态保存到文件中。接着,我们从文件中恢复了这个对象的状态,并打印出来。

  • 相关阅读:
    《嵌入式 - 深入剖析STM32》STM32 启动流程详解(GCC)
    德迅云安全数据库审计——如何保障企业数据库安全
    TCP和UDP、TCP三次握手、TCP为什么要进行三次握手不是两次、TCP四次挥手、TCP和UDP的区别、TCP抓包分析、TCP什么时候三次挥手
    Python注释及PEP 8编码规范
    思科防火墙高级应用
    UDP-GlcNAc,UDPAG,尿苷二磷酸-N-乙酰基葡萄糖胺,UDP-N-乙酰葡糖胺
    【Linux】Linux上的一些软件安装与环境配置(Centos7配置JDK、Hadoop)
    feign 全局 与 局部拦截器的区分与使用
    python实战故障诊断之CWRU数据集(一):数据集初识
    高效代码编辑器gvim的安装使用和配置
  • 原文地址:https://blog.csdn.net/miaoyl1234/article/details/134373158