【设计模式】备忘录模式

article/2025/11/11 17:09:06

设计模式总结链接


备忘录模式又叫做快照模式(Snapshot Pattern)或Token模式,是对象的行为模式。
  备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。


一。简解

备忘录模式可以理解为一种用于记录的模式(历史记录),平时使用的world,ppt等软件都有这种记录历史的功能,能够很好的切换到之前某个节点。
这种记录也可以和事务处理相结合,事务处理中牵扯都回滚功能,就可以使用备忘录模式。


二。用途

备忘录模式主要是用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。


三。实例

备忘录模式的结构图如下所示
这里写图片描述

 备忘录模式所涉及的角色有三个:备忘录(Memento)角色、发起人(Originator)角色、负责人(Caretaker)角色。

  • 备忘录(Memento)角色 

    (1)将发起人(Originator)对象的内战状态存储起来。备忘录可以根据发起人对象的判断来决定存储多少发起人(Originator)对象的内部状态。
     (2)备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。、

  • 备忘录有两个等效的接口:

    窄接口:负责人(Caretaker)对象(和其他除发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),这个窄接口只允许它把备忘录对象传给其他的对象。
    宽接口:与负责人对象看到的窄接口相反的是,发起人对象可以看到一个宽接口(wide interface),这个宽接口允许它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态。

  • 发起人(Originator)角色 

    (1)创建一个含有当前的内部状态的备忘录对象。
    (2)使用备忘录对象存储其内部状态。

  • 负责人(Caretaker)角色

    (1)负责保存备忘录对象。
    (2)不检查备忘录对象的内容。



  “白箱”备忘录模式的实现
  备忘录角色对任何对象都提供一个接口,即宽接口,备忘录角色的内部所存储的状态就对所有对象公开。因此这个实现又叫做“白箱实现”。
  “白箱”实现将发起人角色的状态存储在一个大家都看得到的地方,因此是破坏封装性的。但是通过程序员自律,同样可以在一定程度上实现模式的大部分用意。因此白箱实现仍然是有意义的。

这里写图片描述
源代码
  发起人角色类,发起人角色利用一个新创建的备忘录对象将自己的内部状态存储起来。

public class Originator {private String state;/*** 工厂方法,返回一个新的备忘录对象*/public Memento createMemento(){return new Memento(state);}/*** 将发起人恢复到备忘录对象所记载的状态*/public void restoreMemento(Memento memento){this.state = memento.getState();}public String getState() {return state;}public void setState(String state) {this.state = state;System.out.println("当前状态:" + this.state);}}

备忘录角色类,备忘录对象将发起人对象传入的状态存储起来。

public class Memento {private String state;public Memento(String state){this.state = state;}public String getState() {return state;}public void setState(String state) {this.state = state;}}

负责人角色类,负责人角色负责保存备忘录对象,但是从不修改(甚至不查看)备忘录对象的内容。

public class Caretaker {private Memento memento;/*** 备忘录的取值方法*/public Memento retrieveMemento(){return this.memento;}/*** 备忘录的赋值方法*/public void saveMemento(Memento memento){this.memento = memento;}
}

客户端角色类

public class Client {public static void main(String[] args) {Originator o = new Originator();Caretaker c = new Caretaker();//改变负责人对象的状态o.setState("On");//创建备忘录对象,并将发起人对象的状态储存起来c.saveMemento(o.createMemento());//修改发起人的状态o.setState("Off");//恢复发起人对象的状态o.restoreMemento(c.retrieveMemento());System.out.println(o.getState());}}

在上面的这个示意性的客户端角色里面,首先将发起人对象的状态设置成“On”,并创建一个备忘录对象将这个状态存储起来;然后将发起人对象的状态改成“Off”;最后又将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态。
  系统的时序图更能够反映出系统各个角色被调用的时间顺序。如下图是将发起人对象的状态存储到白箱备忘录对象中去的时序图。
这里写图片描述
可以看出系统运行的时序是这样的:
  

(1)将发起人对象的状态设置成“On”。
(2)调用发起人角色的createMemento()方法,创建一个备忘录对象将这个状态存储起来。
(3)将备忘录对象存储到负责人对象中去。

  将发起人对象恢复到备忘录对象所记录的状态的时序图如下所示:
  这里写图片描述
可以看出,将发起人对象恢复到备忘录对象所记录的状态时,系统的运行时序是这样的:
  

(1)将发起人状态设置成“Off”。
(2)将备忘录对象从负责人对象中取出。
(3)将发起人对象恢复到备忘录对象所存储起来的状态,即“On”状态。



“黑箱”备忘录模式的实现
  备忘录角色对发起人(Originator)角色对象提供一个宽接口,而为其他对象提供一个窄接口。这样的实现叫做“黑箱实现”。
  在JAVA语言中,实现双重接口的办法就是将备忘录角色类设计成发起人角色类的内部成员类。
  将Memento设成Originator类的内部类,从而将Memento对象封装在Originator里面;在外部提供一个标识接口MementoIF给Caretaker以及其他对象。这样,Originator类看到的是Menmento的所有接口,而Caretaker以及其他对象看到的仅仅是标识接口MementoIF所暴露出来的接口。

  使用内部类实现备忘录模式的类图如下所示。
这里写图片描述
源代码
  发起人角色类Originator中定义了一个内部的Memento类。由于此Memento类的全部接口都是私有的,因此只有它自己和发起人类可以调用。

package memento.sample2;/*** @author chen_dz* @date :2012-6-2 上午10:11:08*/
public class Originator {private String state;public String getState() {return state;}public void setState(String state) {this.state = state;System.out.println("赋值状态:" + state);}/*** 工厂方法,返还一个新的备忘录对象*/public MementoIF createMemento(){return new Memento(state);}/*** 发起人恢复到备忘录对象记录的状态*/public void restoreMemento(MementoIF memento){this.setState(((Memento)memento).getState());}private class Memento implements MementoIF{private String state;/*** 构造方法*/private Memento(String state){this.state = state;}private String getState() {return state;}private void setState(String state) {this.state = state;}}
}

窄接口MementoIF,这是一个标识接口,因此它没有定义出任何的方法。

public interface MementoIF {}

负责人角色类Caretaker能够得到的备忘录对象是以MementoIF为接口的,由于这个接口仅仅是一个标识接口,因此负责人角色不可能改变这个备忘录对象的内容。

public class Caretaker {private MementoIF memento;/*** 备忘录取值方法*/public MementoIF retrieveMemento(){return memento;}/*** 备忘录赋值方法*/public void saveMemento(MementoIF memento){this.memento = memento;}
}

客户端角色类

public class Client {public static void main(String[] args) {Originator o = new Originator();Caretaker c = new Caretaker();//改变负责人对象的状态o.setState("On");//创建备忘录对象,并将发起人对象的状态存储起来c.saveMemento(o.createMemento());//修改发起人对象的状态o.setState("Off");//恢复发起人对象的状态o.restoreMemento(c.retrieveMemento());}}

 客户端首先

  (1)将发起人对象的状态设置为“On”。
  (2)调用createMemento()方法,创建一个备忘录对象将这个状态存储起来(此时createMemento()方法还回的明显类型是MementoIF接口,真实类型为Originator内部的Memento对象)。
  (3)将备忘录对象存储到负责人对象中去。由于负责人对象拿到的仅是MementoIF接口,因此无法读出备忘录对象内部的状态。
  (4)将发起人对象的状态设置为“Off”。
  (5)调用负责人对象的retrieveMemento()方法将备忘录对象取出。注意此时仅能得到MementoIF接口,因此无法读出此对象的内部状态。
  (6)调用发起人对象的restoreMemento()方法将发起人对象的状态恢复成备忘录对象所存储的起来的状态,即“On”状态。由于发起人对象的内部类Memento实现了MementoIF接口,这个内部类是传入的备忘录对象的真实类型,因此发起人对象可以利用内部类Memento的私有接口读出此对象的内部状态。



  多重检查点
  前面所给出的白箱和黑箱的示意性实现都是只存储一个状态的简单实现,也可以叫做只有一个检查点。常见的系统往往需要存储不止一个状态,而是需要存储多个状态,或者叫做有多个检查点。
  备忘录模式可以将发起人对象的状态存储到备忘录对象里面,备忘录模式可以将发起人对象恢复到备忘录对象所存储的某一个检查点上。下面给出一个示意性的、有多重检查点的备忘录模式的实现。

源代码
发起人角色源代码

public class Originator {private List<String> states;//检查点指数private int index;/*** 构造函数*/public Originator(){states = new ArrayList<String>();index = 0;}/*** 工厂方法,返还一个新的备忘录对象*/public Memento createMemento(){return new Memento(states , index);}/*** 将发起人恢复到备忘录对象记录的状态上*/public void restoreMemento(Memento memento){states = memento.getStates();index = memento.getIndex();}/*** 状态的赋值方法*/public void setState(String state){states.add(state);index++;}/*** 辅助方法,打印所有状态*/public void printStates(){for(String state : states){System.out.println(state);}}
}

备忘录角色类,这个实现可以存储任意多的状态,外界可以使用检查点指数index来取出检查点上的状态。 

public class Memento {private List<String> states;private int index;/*** 构造函数*/public Memento(List<String> states , int index){this.states = new ArrayList<String>(states);this.index = index;}public List<String> getStates() {return states;}public int getIndex() {return index;}}

负责人角色类

public class Caretaker {private Originator o;private List<Memento> mementos = new ArrayList<Memento>();private int current;/*** 构造函数*/public Caretaker(Originator o){this.o = o;current = 0;}/*** 创建一个新的检查点*/public int createMemento(){Memento memento = o.createMemento();mementos.add(memento);return current++;}/*** 将发起人恢复到某个检查点*/public void restoreMemento(int index){Memento memento = mementos.get(index);o.restoreMemento(memento);}/*** 将某个检查点删除*/public void removeMemento(int index){mementos.remove(index);}
}

客户端角色源代码

public class Client {public static void main(String[] args) {Originator o = new Originator();Caretaker c = new Caretaker(o);//改变状态o.setState("state 0");//建立一个检查点c.createMemento();//改变状态o.setState("state 1");//建立一个检查点c.createMemento();//改变状态o.setState("state 2");//建立一个检查点c.createMemento();//改变状态o.setState("state 3");//建立一个检查点c.createMemento();//打印出所有检查点o.printStates();System.out.println("-----------------恢复检查点-----------------");//恢复到第二个检查点c.restoreMemento(2);//打印出所有检查点o.printStates();}}

运行结果如下:
这里写图片描述

可以看出,客户端角色通过不断改变发起人角色的状态,并将之存储在备忘录里面。通过指明检查点指数可以将发起人角色恢复到相应的检查点所对应的状态上。

  将发起人的状态存储到备忘录对象中的活动序列图如下:

  这里写图片描述

系统运行的时序是这样的:
  (1)将发起人对象的状态设置成某个有效状态;
  (2)调用负责人角色的createMemento()方法,负责人角色会负责调用发起人角色和备忘录角色,将发起人对象的状态存储起来。

  将发起人对象恢复到某一个备忘录对象的检查点的活动序列图如下:
这里写图片描述

  由于负责人角色的功能被增强了,因此将发起人对象恢复到备忘录对象所记录的状态时,系统运行的时序被简化了:
  调用负责人角色的restoreMemento()方法,将发起人恢复到某个检查点。



“自述历史”模式
  所谓“自述历史”模式(History-On-Self Pattern)实际上就是备忘录模式的一个变种。在备忘录模式中,发起人(Originator)角色、负责人(Caretaker)角色和备忘录(Memento)角色都是独立的角色。虽然在实现上备忘录类可以成为发起人类的内部成员类,但是备忘录类仍然保持作为一个角色的独立意义。在“自述历史”模式里面,发起人角色自己兼任负责人角色。

“自述历史”模式的类图如下所示:
这里写图片描述

备忘录角色有如下责任:

(1)将发起人(Originator)对象的内部状态存储起来。
(2)备忘录可以保护其内容不被发起人(Originator)对象之外的任何对象所读取。

发起人角色有如下责任:

(1)创建一个含有它当前的内部状态的备忘录对象。
(2)使用备忘录对象存储其内部状态。
客户端角色有负责保存备忘录对象的责任。

源代码
窄接口MementoIF,这是一个标识接口,因此它没有定义出任何的方法。

public interface MementoIF {}

发起人角色同时还兼任负责人角色,也就是说它自己负责保持自己的备忘录对象。

public class Originator {public String state;/*** 改变状态*/public void changeState(String state){this.state = state;System.out.println("状态改变为:" + state);}/*** 工厂方法,返还一个新的备忘录对象*/public Memento createMemento(){return new Memento(this);}/*** 将发起人恢复到备忘录对象所记录的状态上*/public void restoreMemento(MementoIF memento){Memento m = (Memento)memento;changeState(m.state);}private class Memento implements MementoIF{private String state;/*** 构造方法*/private Memento(Originator o){this.state = o.state;}private String getState() {return state;}}
}

客户端角色类

public class Client {public static void main(String[] args) {Originator o = new Originator();//修改状态o.changeState("state 0");//创建备忘录MementoIF memento = o.createMemento();//修改状态o.changeState("state 1");//按照备忘录恢复对象的状态o.restoreMemento(memento);}}

由于“自述历史”作为一个备忘录模式的特殊实现形式非常简单易懂,它可能是备忘录模式最为流行的实现形式。


四。优点

使用备忘录模式,可以避免暴露一些只应由源发器管理却又必须存储在源发器之外的信息,而且能够在对象需要时恢复到先前的状态。


五。不足

使用备忘录可能代价很高。如果源发器在生成备忘录时必须复制并存储大量的信息,或者客户非常频繁地创建备忘录和恢复源发器状态,可能会导致非常大的开销。


http://chatgpt.dhexx.cn/article/cNNxOcOo.shtml

相关文章

23种设计模式——备忘录模式

目录 备忘录模式&#xff08;Memento&#xff09; UML图 示例代码 适用场景 优缺点 备忘录模式和原型模式 例子——游戏进度存档 例子——象棋中的悔棋 备忘录模式&#xff08;Memento&#xff09; 本质&#xff1a;保存和恢复内部状态 备忘录模式&#xff1a;在不破坏…

23种设计模式之---备忘录模式

前言 网上搜索备忘录设计模式&#xff0c;基本上均是在一个GoF&#xff0c;基础上衍生下来的。为了避免重复造轮子&#xff0c;这里会结合网上demo&#xff0c;和自己理解进行总结 定义&#xff1a;备忘录&#xff08;Memento&#xff09;模式又称标记&#xff08;Token&…

备忘录模式介绍

备忘录模式介绍 一、基本介绍二、代码实现三、UML类图四、备忘录模式小结其他设计模式 一、基本介绍 备忘录模式&#xff08;Memento Pattern&#xff09;属于行为型模式&#xff0c;是指在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外…

设计模式 | 备忘录模式及典型应用

本文的主要内容&#xff1a; 介绍备忘录模式示例备忘录模式总结 备忘录模式 备忘录模式经常可以遇到&#xff0c;譬如下面这些场景&#xff1a; 浏览器回退&#xff1a;浏览器一般有浏览记录&#xff0c;当我们在一个网页上点击几次链接之后&#xff0c;可在左上角点击左箭头…

设计模式之备忘录模式

一、备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;保存一个对象的某个状态&#xff0c;以便在适当的时候恢复对象。备忘录模式属于行为型模式。 原发器(Originator)角色&#xff1a;原发器根据需要决定将自己的哪些内部状态保存到备忘录中&#xff0c;并可以使…

备忘录模式(Java)

备忘录模式&#xff08;Java&#xff09; 下面是关于我所写的所有设计模式代码&#xff08;还是建议自己手打或者想一个别的例子练习一次&#xff09; (https://github.com/lihang212010/DesignPatterns-/tree/master/designpatterns/src) 先来张百度的UML 下面是我例子的U…

撤销功能的实现——备忘录模式(二)

21.2 备忘录模式概述 备忘录模式提供了一种状态恢复的实现机制&#xff0c;使得用户可以方便地回到一个特定的历史步骤&#xff0c;当新的状态无效或者存在问题时&#xff0c;可以使用暂时存储起来的备忘录将状态复原&#xff0c;当前很多软件都提供了撤销(Undo)操作&#xff0…

18-备忘录模式

文章目录 游戏角色状态恢复问题备忘录模式基本介绍备忘录模式解决游戏角色状态回复问题备忘录模式的注意事项和细节 游戏角色状态恢复问题 游戏鱼色有攻击力和防御力&#xff0c;在大战 Boss 前保存自身的状态&#xff08;攻击力和防御力&#xff09;&#xff0c;当大战 Boss …

详解设计模式:备忘录模式

详解设计模式&#xff1a;备忘录模式 备忘录模式&#xff08;Memento Pattern&#xff09;也被称为快照模式&#xff08;Snapshot Pattern&#xff09;、Token 模式&#xff08;Token Pattern&#xff09;&#xff0c;是在 GoF 23 种设计模式中定义了的行为型模式。 备忘录模式…

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

目录 一、什么是备忘录模式 二、备忘录模式的结构 三、备忘录模式的适用性 四、备忘录模式的实现 五、备忘录模式的优缺点 六、总结 一、什么是备忘录模式 备忘录(Memento)模式又叫作快照(Snapshot)模式或Token模式&#xff0c;是一种对象的行为模式。在备忘录模式里&am…

设计模式之备忘录模式(C++)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 一、备忘录模式是什么&#xff1f; 备忘录模式是一种行为型的软件设计模式&#xff0c;在不破坏封装的前提下&#xff0c;获取一个…

什么是备忘录模式?

一、定义 备忘录模式又称快照模式&#xff0c;或者令牌模式。是指在不破坏封装的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态&#xff0c;属于行为型模式。 二、通用写法及其uml 发起人角色&a…

行为型模式——备忘录模式(Memento Pattern)

文章目录 备忘录模式&#xff08;Memento Pattern&#xff09;什么是备忘录模式&#xff1f;UML角色应用使用模板 为什么要使用备忘录模式&#xff1f;优点&#xff1a;缺点&#xff1a; 怎样使用备忘录模式&#xff1f;在JDK中的使用 备忘录模式&#xff08;Memento Pattern&a…

备忘录模式

一、备忘录模式 1、定义 备忘录模式&#xff08;Memento Pattern&#xff09;又称作快照模式&#xff08;Snapshot Pattern&#xff09;&#xff0c;指在不破坏封装的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在对象之外保存这个状态。这样以后就可将该对象恢复…

设计模式系列----备忘录模式

一、什么是备忘录模式 备忘录这个词汇大家应该都不陌生&#xff0c;我就经常使用备忘录来记录一些比较重要的或者容易遗忘的信息&#xff0c;与之相关的最常见的应用有许多&#xff0c;比如游戏存档&#xff0c;我们玩游戏的时候肯定有存档功能&#xff0c;旨在下一次登录游戏时…

基于MIMO讲解信道估计基本原理

为什么要进行信道估计&#xff1f; 信号在通过信道传输的时候&#xff0c;会受到信道中种种因素产生的噪声以及可能发生的多径效应&#xff0c;弄清信号经过的信道的特性&#xff0c;表征信道的技术/过程称为信道估计&#xff08;Channel Estimation&#xff09;。 注&#xf…

m基于深度学习的OFDM信道估计和均衡算法误码率matlab仿真,对比了LS,MMSE以及LMMSE等传统的信道估计算法

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 随着无线通信的快速发展,5G正逐渐成长为支撑全社会各行业运作的大型基础性互联网络,其服务范围的大幅扩展对底层技术提出了诸多挑战,尤其是作为物理层关键技术之一的正交频分复用(Orthogonal Fre…

IRS的信道估计基础代码

一、 智能反射平面&#xff08;intelligent reflecting surfaces&#xff09;是一种被动反射表面&#xff0c;其具有的特性是可控制反射信号的相位。 明确IRS是可控制反射信号的相位&#xff0c;所以以单个智能反射单元为例&#xff0c;该单元可调信号的参数可表示为​&#xf…

信道估计算法

目前我所涉及的是短波宽带无线信道下的接收端的处理&#xff0c;包括捕获、同步、信道估计及信道均衡&#xff0c;还有译码。百度百科里是这样解释这种信道的&#xff1a;短波通信发射电波要经电离层的反射才能到达接收设备&#xff0c;通信距离较远&#xff0c;是远程通信的主…

信道估计之LS算法

信道估计之LS算法 前言LS信道估计的原理总结 前言 信道估计是通信系统接收机的重要功能模块&#xff0c;主要是用来估计信号所经历信道的冲击响应&#xff0c;并用于后续的信道均衡处理&#xff0c;以便消除多径信号混叠造成的ISI。 信道估计的方法有很多种&#xff0c;…