七爪源码:学习 Memento 设计模式

七爪源码:学习 Memento 设计模式

Memento 是一种行为设计模式,可让您保存和恢复对象的先前状态,而无需透露其实现的细节。

假设您正在创建一个文本编辑器应用程序。除了编写文本之外,文本编辑器的基本要求之一是能够撤消所做的更改。

因此,您决定使用直接实现,在该实现中,在执行任何操作之前,应用程序会记录所有对象的状态并将其存储在某处。因此,当用户决定恢复操作时,应用程序会从历史记录中检索最新的快照

对象中所有字段的值都需要复制到存储中。但是,这只有在对象放宽对其内容的访问限制时才有可能,而现实生活中并非如此。

Memento 设计模式

损坏的封装是我们刚刚遇到的问题的原因。对象有时会尝试做比他们应该做的更多的事情。为了收集执行特定操作所需的数据,它们会侵入其他对象的私有空间,而不是让这些对象执行操作。

Memento 模式将创建状态快照的责任委托给状态的实际所有者,即创建者对象。因此,其他对象不应该尝试复制编辑器的状态。

该模式建议将对象状态的副本存储在特殊的纪念品中。纪念品的内容只能由产生它的对象访问。 Mementos 必须通过有限的接口与其他对象通信,该接口允许获取快照的元数据,但不能获取原始对象的状态。

在这种限制性政策下,纪念品可以存储在其他对象中,通常称为看守者。看守者对纪念品的访问权限有限,因此它无法更改其状态。同样,发起者可以访问备忘录中的所有字段,允许它随意恢复其先前的状态。

在实现撤销时,命令和备忘录设计模式可以一起使用。命令负责对目标对象执行各种操作,而备忘录在命令执行之前记录该对象的状态。

UML 类图

实施步骤

  • 确定哪个类将是发起者。了解程序是使用一个中心对象还是许多较小的对象至关重要。
  • 创建一个名为 Memento 的类。一个一个地声明一组与 originator 类中的字段相对应的字段。
  • 使内存类不可变。 Mementos 应该只通过构造函数接受一次数据。该类不应该有二传手。
  • 如果您的编程语言支持嵌套类,则将备忘录嵌套在创建者中。如果没有,则从 memento 类中提取一个空白接口,并让所有其他对象使用它来引用 memento。您可能会向接口添加一些元数据操作,但不能添加任何暴露发起者状态的操作。
  • 向创建者类添加一个方法来制作纪念品。发起者应通过一个或多个参数将其状态传递给备忘录的构造函数。该方法的返回类型应该是您在上一步中提取的接口的返回类型。 memento-production 方法应该直接与 memento 类一起使用。
  • 添加一个用于将创建者的状态恢复到类的方法。该方法应该接受一个纪念品对象作为参数。如果您在上一步中提取了接口,请将其设为参数。因为发起者需要访问传入的对象,所以需要进行类型转换。
  • 不管看守者是代表命令对象、历史还是完全不同的东西,它都应该知道何时向发起者请求新的纪念品,如何存储它们,以及何时用特定的纪念品恢复发起者。
  • 我们可以将看守者和发起者之间的链接移到纪念品类中。因此,每个纪念品都必须与创建它的创建者相关联。恢复也将转移到纪念品类。只有当 memento 类嵌套在 originator 类中或者 originator 类提供了足够的 setter 来覆盖其状态时,这一切才有意义。
  • 源代码实现

    需要时,Editor (Originator) 类可以创建其自身状态的快照以及从快照中恢复其状态。

    Memento 是一个值对象,充当发起者当前状态的快照。使备忘录不可变并且只通过构造函数传递一次数据是很常见的。

    package com.learncsdesign;public class Editor {private String text;private int cursorX;private int cursorY;private int selectionWidth;public void setText(String text) {this.text = text;}public String getText() {return text;}public void setCursor(int cursorX, int cursorY) {this.cursorX = cursorX;this.cursorY = cursorY;}public void setSelectionWidth(int selectionWidth) {this.selectionWidth = selectionWidth;}public Snapshot save() {return new Snapshot(text, cursorX, cursorY, selectionWidth);}public void restore(Snapshot snapshot) {setText(snapshot.getText());setCursor(snapshot.getCursorX(), snapshot.getCursorY());setSelectionWidth(snapshot.getSelectionWidth());}class Snapshot {private final String text;private final int cursorX;private final int cursorY;private final int selectionWidth;private Snapshot(String text, int cursorX, int cursorY, int selectionWidth) {this.text = text;this.cursorX = cursorX;this.cursorY = cursorY;this.selectionWidth = selectionWidth;}public String getText() {return text;}public int getCursorX() {return cursorX;}public int getCursorY() {return cursorY;}public int getSelectionWidth() {return selectionWidth;}}}

    除了知道何时以及为什么要捕获发起者的状态之外,看守者还知道何时恢复它。 看守者可以通过存储纪念品来跟踪发起者的历史。 当发起者必须及时返回时,看守者从堆栈中检索最顶部的 memento 并将其传递给发起者的恢复方法。

    package com.learncsdesign;import java.util.Stack;import com.learncsdesign.Editor.Snapshot;public class CareTaker {private static Stack snapshots = new Stack();private static void doBackup(Editor editor) {snapshots.push(editor.save());}private static void undo(Editor editor) {if (!snapshots.isEmpty()) {editor.restore(snapshots.pop());}}public static void main(String[] args) {Editor editor = new Editor();editor.setText(“Hello World!”);System.out.println(“Editor text: ” + editor.getText());doBackup(editor);editor.setText(“Hello Medium!”);System.out.println(“Editor modified text: ” + editor.getText());undo(editor);System.out.println(“Editor Restored text: ” + editor.getText());}}

    memento 类嵌套在这个实现中的 originator 类中。发起者可以访问备忘录的字段和方法,即使它们已被声明为私有。尽管如此,看守者对纪念品的字段和方法的访问非常有限,这允许它在不改变其状态的情况下将纪念品存储在堆栈上。

    何时应用 Memento 设计模式

    • 当您需要创建对象状态的快照以便能够将其恢复到以前的状态时,请使用 Memento 模式。
    • 每当直接访问对象的字段违反其封装时,请使用此模式。 Memento 使对象本身负责拍摄其状态的快照。快照不能被任何其他对象读取,因此原始对象的状态数据是安全可靠的。

    Memento 设计模式的优点

    • 可以在不违反其封装的情况下创建对象状态的快照。
    • 让看守者维护发起者状态的历史,以便简化发起者的代码。

    如果你喜欢这篇文章,你知道该怎么做

    关注七爪网,获取更多APP/小程序/网站源码资源!

    郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
    (0)
    用户投稿
    上一篇 2022年6月20日
    下一篇 2022年6月20日

    相关推荐

    • Mysql分布式事务

      Mysql分布式事务 为了规范分布式事务的管理,X/OPEN 提出了分布式事务处理规范XA协议,XA规范了TM与RM之间的通信接口,在TM与多个RM之间形成一个双向通信桥梁,从而在…

      2022年6月17日
    • 日常纠结,合资车中轩逸和雷凌选哪台更适合家用?

      老实说,这两款车也曾是很多人的纠结对象,如果你也一样不知道哪款更值得买,不妨看看下面的这个对比,我选了雷凌2021款185T CVT运动版,对比轩逸2021款1.6L XL CVT…

      2022年7月24日
    • 综艺忘开美颜名场面!baby的法令纹、张雨绮的浮肿,暴露本来面目

      如今真人秀里的明星,硬生生被美颜磨皮成了“雾里看花”的状态,真人秀变“假人秀”。而当综艺不小心关掉美颜滤镜,你猜尴尬的会是谁? 《跑男》的滤镜出了名得越加越重,两位常驻女星在镜头下…

      2022年9月1日
    • 72岁王薇薇真敢穿!露脐装配高筒袜玩年轻,面部状态暴露真实年龄

      有人总是在纠结身材太胖,到底该怎么穿?但是有人却在纠结太骨感的身材怎么办?其实根本就没有完美的身材,而是需要通过正确的服装搭配,才能够展现出最完美的自己。如今72岁的“婚纱女王”王…

      2022年7月3日
    • 怎么享受教育优惠(教育优惠怎么用)

      今天分享的是大学生如何使用教育优惠购买iPad 感兴趣的话,往下看吧 众所周知,iPad是可以成为生产力的,也是近年来最受广大大学生欢迎的。 大学生是可以通过学生认证,享受教育优惠…

      2022年11月1日
    • 北京首钢三外援正式确定,解立彬仍愁无人可用,曾凡博或成为核心

      这个夏天首钢男篮做出了比较大的调整,在被吉林淘汰之后他们进行了反思,这几年成绩一直下滑的原因究竟是什么?如今解立彬成为了球队的新帅,而且首钢已经多个老将离队,包括曾经的防守悍将王骁…

      2022年7月21日
    • 离婚3年,曝马伊琍有新家庭,文章复出排话剧,与谢娜搭戏状态佳

      有句话说得好“日久生情”,这对于明星来说简直是个考验。艺人们为了赚钱,每天都需要见不同的人,甚至为了一部剧能让两个陌生的人,在一个剧组呆好几个月,不产生感情才怪。 文章和姚笛就是因…

      2022年8月21日
    • 六尾solo赛全胜拿下!极限操作令明眸质疑:你是不是开脚本了?

      相信很多的网友们对于高人气主播六尾一定非常熟悉,在平时直播的时候,六尾就经常会给粉丝们展示自己的操作,不得不说,六尾的守约确实是很厉害的,可以说六尾已经是国服公认的百里守约天花板了…

      2022年8月24日
    • 愉悦之境,感知存在的终极目的

      曾睿:《感知随想录》(56) 为什么要感知愉悦? 什么是感知愉悦?不要以为笑一笑就是感知愉悦,不要以为完成了某个任务就是感知愉悦,不要以为突然得到做梦都想要得到的东西就是感知愉悦,…

      2022年8月18日
    • 管理订单状态,该上状态机吗?

      前言 在平常的后端项目开发中,状态机模式的使用其实没有大家想象中那么常见,笔者之前由于不在电商领域工作,很少在业务代码中用状态机来管理各种状态,一般都是手动get/set状态值。去…

      2022年7月1日

    联系我们

    联系邮箱:admin#wlmqw.com
    工作时间:周一至周五,10:30-18:30,节假日休息