笔记 笔记
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

EasT-Duan

Java 开发
首页
  • 开发工具
  • Java Web
  • Java 进阶
  • 容器化技术
  • Java 专栏

    • Java 核心技术面试精讲
    • Java 业务开发常见错误 100 例
  • 数据库专栏

    • MySQL 实战 45 讲
    • Redis 核心技术与实战
  • 安全专栏

    • OAuth 2.0 实战课
  • 计算机系统
  • 程序设计语言
  • 数据结构
  • 知识产权
  • 数据库
  • 面向对象
  • UML
  • 设计模式
  • 操作系统
  • 结构化开发
  • 软件工程
  • 计算机网络
  • 上午题错题
在线工具 (opens new window)

购买兑换码请添加

添加时候请写好备注,否则无法通过。

  • 设计模式

    • 简介

    • 原则

    • UML

    • 创建型

    • 结构型

    • 行为型

      • 模板模式
      • 命令模式
      • 访问者模式
      • 迭代器模式
      • 中介者模式
      • 备忘录模式
        • 简介
        • 代码示例
          • 一个备忘录
          • 多个备忘录
        • 说明
      • 解释器模式
      • 状态模式
      • 策略模式
      • 职责链模式
  • JVM 详解

  • Linux

  • Redis

  • 分布式锁

  • Shiro

  • Gradle

  • Java 进阶
  • 设计模式
  • 行为型
EasT-Duan
2023-11-30
目录

备忘录模式

欢迎来到我的 ChatGPT 中转站,极具性价比,为付费不方便的朋友提供便利,有需求的可以添加左侧 QQ 二维码,另外,邀请新用户能获取余额哦!最后说一句,那啥:请自觉遵守《生成式人工智能服务管理暂行办法》。

# 简介

备忘录模式(Memento Pattern)在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保 存的状态。

可以这里理解备忘录模式:现实生活中的备忘录是用来记录某些要去做的事情, 或者是记录已经达成的共同意见的事情,以防忘记了。而在软件层面,备忘录式有着相同的含义,备忘录对象主要用来记录一个对象的某种状态,或者某 些数据,当要做回退时,可以从备忘录对象里获取原来的数据进行恢复操作。

步骤流程为:

  1. 发起人创建备忘录: 发起人在需要保存当前状态时,创建一个备忘录对象,并将自己的状态保存到备忘录中。
  2. 发起人传递备忘录给负责人: 发起人将备忘录传递给负责人,负责人负责存储备忘录对象。
  3. 发起人从备忘录中恢复状态: 当需要恢复到之前的状态时,发起人从负责人那里获取相应的备忘录,并使用备忘录中的状态进行恢复。

备忘录模式中的几个重要角色

  • 发起人(Originator): 发起人是拥有内部状态的对象,它需要在不破坏封装性的前提下捕获自己的内部状态,并且能够根据备忘录恢复到之前的状态。发起人负责创建备忘录和在备忘录中存储自身状态。

  • 备忘录(Memento): 备忘录是用于存储发起人对象状态的对象。备忘录提供了一个窄接口,只能由发起人对象访问。通常,备忘录具有获取和设置发起人状态的方法,但不允许直接修改状态。这样,可以确保发起人的状态不会被外部对象直接访问或修改。

  • 负责人(Caretaker): 负责人是负责存储和管理备忘录的对象。负责人可以持有一个或多个备忘录,并且只有在需要时才能将备忘录传递给发起人。负责人允许发起人恢复到不同的状态,但本身并不了解备忘录的具体内容。

# 代码示例

# 一个备忘录

/**
 * 原发器,也就是我们需要保存状态的对象。它可以创建一个备忘录,用于保存其当前状态,也可以使用备忘录来恢复其状态。
 */
@Data
public class Originator {
    // 状态,提供set和get方法
    private String state;

    // 保存,返回一个memento,用来从中恢复
    public Memento saveToMemento() {
        return new Memento(state);
    }

    // 恢复
    public void restoreFromMemento(Memento memento) {
        state = memento.getSavedState();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
 * 备忘录,用于存储原发器的内部状态。备忘录应该防止Originator以外的其他对象访问备忘录。
 * 备忘录有两个接口,Caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需要的所有数据。
 */
public class Memento {
    private final String state;

    public Memento(String state) {
        this.state = state;
    }

    //恢复
    public String getSavedState() {
        return state;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
 * 负责人,负责保存备忘录。它可以保存一个或多个备忘录对象,但不能操作和检查备忘录的内容。
 */
public class Caretaker {
    private final List<Memento> mementoList = new ArrayList<>();


    public void addMemento(Memento memento) {
        mementoList.add(memento);
    }

    public Memento getMemento(int index) {
        return mementoList.get(index);
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Client {

    public static void main(String[] args) {
        // 创建一个原发器
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();
        originator.setState("状态 1");
        System.out.println(originator.getState());
        // 保存状态
        Memento memento = originator.saveToMemento();
        caretaker.addMemento(memento);
        // 修改
        System.out.println("修改一下吧");
        originator.setState("状态 2");
        caretaker.addMemento(originator.saveToMemento());
        System.out.println(originator.getState());


        // 恢复
        originator.restoreFromMemento(caretaker.getMemento(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
20
21
22
23

# 多个备忘录

需求:游戏角色有攻击力和防御力,在大战 Boss 前保存自身的状态(攻击力和防御力),当大战 Boss 后攻击力和防御力下降,从备忘录对象恢复到大战前的状态。

/**
 * 发起者
 */
@Data
public class Originator {
    private String name;
    private int vit;
    private int def;

    public Originator(String name, int vit, int def) {
        this.name = name;
        this.vit = vit;
        this.def = def;
        System.out.println("当前角色为:" + name + ",攻击力为:" + vit + ",防御力为:" + def);
    }

    // 保存到备忘录
    public Memento saveToMemento() {
        return new Memento(vit, def);
    }

    // 从备忘录恢复
    public void restoreFromMemento(Memento memento) {
        this.vit = memento.getVit();
        this.def = memento.getDef();
        System.out.println("当前角色为:" + name + ",攻击力为:" + vit + ",防御力为:" + def);
    }
}
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
/**
 * 备忘录
 */
@Data
public class Memento {
    private int vit;
    private int def;

    public Memento(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Caretaker {
    //如果希望保存多个originator对象的不同时间的状态
    private final HashMap<String, HashMap<String, Memento>> mementos = new HashMap<>();

    /**
     * 添加备忘录
     * @param originatorId      角色
     * @param mementoId         当前时间
     * @param memento           当前状态
     */
    public void addMemento(String originatorId, String mementoId, Memento memento) {
        // 根据角色查询对应的集合,如果存在就返回,不存在就创建一个新的集合
        HashMap<String, Memento> originatorMementos = mementos.getOrDefault(originatorId, new HashMap<>());
        originatorMementos.put(mementoId, memento);
        mementos.put(originatorId, originatorMementos);
    }

    // 获取备忘录
    public Memento getMemento(String originatorId, String mementoId) {
        HashMap<String, Memento> originatorMementos = mementos.get(originatorId);
        if (originatorMementos == null) {
            return null;
        }
        return originatorMementos.get(mementoId);
    }
}
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
public class Client {
    public static void main(String[] args) {
        Caretaker caretaker = new Caretaker();
        String name1 = "东东";
        String name2 = "西西";
        System.out.println("BOSS战开始前");
        Originator originator1 = new Originator(name1, 100, 100);
        Originator originator2 = new Originator(name2, 50, 50);
        //保存状态
        caretaker.addMemento(name1, "BOSS战开始前", originator1.saveToMemento());
        caretaker.addMemento(name2, "BOSS战开始前", originator2.saveToMemento());

        // BOSS战后
        System.out.println("BOSS战结束后");
        originator1.setVit(50);
        originator1.setDef(50);
        originator2.setVit(30);
        originator2.setDef(30);
        caretaker.addMemento(name1, "BOSS战结束后", originator1.saveToMemento());
        caretaker.addMemento(name2, "BOSS战结束后", originator2.saveToMemento());

        // 休息,回满血
        System.out.println("休息,回满血");
        originator1.setVit(200);
        originator1.setDef(200);
        originator2.setVit(100);
        originator2.setDef(100);


        // 恢复状态--开战之前
        System.out.println("恢复到BOSS战前");
        Memento memento = caretaker.getMemento(name1, "BOSS战开始前");
        originator1.restoreFromMemento(memento);

    }
}
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

# 说明

  • 给用户提供了一种可以恢复状态的机制,可以使用户能够比较方便地回到某个历史的状态。
  • 实现了信息的封装,使得用户不需要关心状态的保存细节。
  • 如果类的成员变量过多,势必会占用比较大的资源,而且每一次保存都会消耗一定的内存,这个需要注意。

适用的应用场景:

  • 后悔药。
  • 打游戏时的存档。
  • Windows 里的 ctrl + z。
  • IE 中的后退。
  • 数据库的事务管理。
  • 为了节约内存,备忘录模式可以和原型模式配合使用。
#设计模式
上次更新: 2025/08/19, 10:30:51
中介者模式
解释器模式

← 中介者模式 解释器模式→

最近更新
01
Reactor 核心
02-24
02
前置条件
10-30
03
计算机网络
09-13
更多文章>
Theme by Vdoing | Copyright © 2019-2025 powered by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式