七爪源码:学习 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)删除。
    用户投稿
    上一篇 2022年6月20日 23:21
    下一篇 2022年6月20日 23:21

    相关推荐

    联系我们

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