• 03-JAVA设计模式-备忘录模式


    备忘录模式

    什么是备忘录模式

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

    主要角色包括:

    • 发起者(Originator):需要保存和恢复状态的对象。它记录当前时刻的内部状态信息,提供创建备忘录和恢复备忘录数据的功能,并可以访问备忘录里的所有信息。
    • 备忘录(Memento):负责存储发起人的内部状态。它是一个临时中间对象,用于存储目标对象的初始相关属性信息。当需要恢复对象的状态时,备忘录提供这些内部状态给发起人。
    • 看护者(Caretaker):对备忘录进行管理,提供保存与获取备忘录的功能。但它不能对备忘录的内容进行访问与修改。

    优点:

    • 状态保存与恢复:备忘录模式可以方便地保存和恢复对象的状态,使得对象的状态变化具有可追溯性。
    • 封装性:通过将对象的状态封装在备忘录对象中,备忘录模式可以保持对象的封装性,不会暴露内部状态给外部对象。
    • 简化撤销和重做操作:在需要实现撤销、重做等功能的场景中,备忘录模式可以大大简化操作,提高代码的清晰度和可维护性。

    缺点:

    • 资源消耗:如果对象的状态较为复杂或状态变化频繁,备忘录模式可能会消耗较多的内存资源来保存状态。
    • 性能开销:频繁地创建和销毁备忘录对象可能会导致一定的性能开销。
    • 设计复杂性:如果对象的状态需要保密或访问权限受限,备忘录模式可能会增加设计的复杂性,并可能破坏对象的封装性。

    常见应用场景:

    • 文本编辑器:在文本编辑器中,备忘录模式可以用于实现撤销和重做功能。当用户编辑文本时,编辑器可以定期保存文本状态到备忘录对象中。当用户需要撤销或重做操作时,编辑器可以恢复或重新应用这些状态。
    • 游戏存档:在电子游戏中,备忘录模式可以用于实现游戏的存档功能。当玩家选择保存游戏时,游戏可以将当前的游戏状态(如玩家位置、分数、物品等)保存到备忘录对象中。当玩家再次加载游戏时,游戏可以从备忘录对象中恢复状态,让玩家继续之前的游戏进度。
    • 数据库事务:在数据库操作中,备忘录模式可以用于实现事务的回滚功能。当执行一系列数据库操作时,可以将数据库的状态保存到备忘录对象中。如果事务执行失败或需要回滚,可以恢复到之前的状态。

    案例

    java实现控制台输入内容的回退

    UML

    在这里插入图片描述

    实现步骤:

    • 创建发起者ScannerInput,定义保存输入内容字段input
    • 创建备忘录继承发起者,主要继承发起者的属性及get/set方法不再重复提供,提供创建备忘录及通过备忘录恢复状态的方法
    • 创建看护者,定义栈对备忘录进行管理,提供保存与获取备忘录的功能。但它不能对备忘录的内容进行访问与修改

    实现代码

    ScannerInput.java

    // 发起者
    public class ScannerInput {
        // 输入内容
        protected String input;
        public ScannerInput(String input) {
            this.input = input;
        }
        public String getInput() {
            return input;
        }
        public void setInput(String input) {
            this.input = input;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Originator.java

    // 备忘录
    //  继承发起者,主要继承发起者的属性及get/set方法不再重复提供
    //  提供创建备忘录及通过备忘录恢复状态的方法
    public class Originator extends ScannerInput{
    
        public Originator(String input) {
            super(input);
        }
    
        // 创建备忘录
        public ScannerInput createMemento() {
            return new ScannerInput(this.input);
        }
    
        // 恢复
        public void restoreMemento(ScannerInput scannerInput) {
            this.input = scannerInput.getInput();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    Caretaker.java

    import java.util.Stack;
    
    // 看护者
    // * 对备忘录进行管理,提供保存与获取备忘录的功能。但它不能对备忘录的内容进行访问与修改。
    public class Caretaker {
        // 定义栈管理备忘录
        private Stack<ScannerInput> stack = new Stack<ScannerInput>();
    
        // 压栈
        public void setScannerInput(ScannerInput scannerInput) {
            stack.push(scannerInput);
        }
    
        // 出栈
        public ScannerInput getScannerInput() {
            if(stack.size() == 0){
                System.out.println("已经不可以回退啦!");
            }
            return stack.pop();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    TestClient.java

    import java.util.Scanner;
    
    public class TestClient {
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入一些文本,输入'exit'退出:");
    
            // 创建原发器对象并设置默认内容
            Originator originator = new Originator("");
            // 创建并保存备忘录
            Caretaker caretaker = new Caretaker();
            // 初始化压栈
            caretaker.setScannerInput(originator.createMemento());
    
            while (true) {
                String input = scanner.nextLine();
                if ("exit".equalsIgnoreCase(input)) {
                    System.out.printf("你输入了:%s%n" , input);
                    break;
                }
                // 回退操作
                else if ("back".equalsIgnoreCase(input)) {
                    // 回退
                    originator.restoreMemento(caretaker.getScannerInput());
                    System.out.printf("回退上一步-你输入:%s%n 输入:back(回退上一步) exit(退出)%n" , originator.getInput());
                } else {
                    // 设置内容
                    originator.setInput(input);
                    // 设置备忘录
                    caretaker.setScannerInput(originator.createMemento());
                    System.out.printf("你输入了:%s%n 输入:back(回退上一步) exit(退出)%n" , originator.getInput());
                }
            }
    
            scanner.close();
            System.out.println("已退出。");
        }
    }
    
    • 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

    执行结果:

    在这里插入图片描述

    gitee源码

    git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

  • 相关阅读:
    无序点云排序
    [H5动画制作系列] Sprite及Text Demo
    1.12反向传播误差到更多层
    GBase 8a MPP集群VC管理之操作VC
    【重要】Heygen订阅指南和用法详解!让照片学说话?一张照片变演讲?Heygen订阅值得吗?
    springcloud集成配置中心报错No spring.config.import set
    第六章 图 九、拓扑排序
    Oracle数据库修改序列,Oracle中的主键值和序列中的值对应不上时的处理方式
    rust cfg的使用
    idea创建Java中的web项目
  • 原文地址:https://blog.csdn.net/u014331138/article/details/138195812