Memento 是一种行为设计模式,可让您保存和恢复对象的先前状态,而无需透露其实现的细节。
假设您正在创建一个文本编辑器应用程序。除了编写文本之外,文本编辑器的基本要求之一是能够撤消所做的更改。
因此,您决定使用直接实现,在该实现中,在执行任何操作之前,应用程序会记录所有对象的状态并将其存储在某处。因此,当用户决定恢复操作时,应用程序会从历史记录中检索最新的快照。
对象中所有字段的值都需要复制到存储中。但是,这只有在对象放宽对其内容的访问限制时才有可能,而现实生活中并非如此。
Memento 设计模式
损坏的封装是我们刚刚遇到的问题的原因。对象有时会尝试做比他们应该做的更多的事情。为了收集执行特定操作所需的数据,它们会侵入其他对象的私有空间,而不是让这些对象执行操作。
Memento 模式将创建状态快照的责任委托给状态的实际所有者,即创建者对象。因此,其他对象不应该尝试复制编辑器的状态。
该模式建议将对象状态的副本存储在特殊的纪念品中。纪念品的内容只能由产生它的对象访问。 Mementos 必须通过有限的接口与其他对象通信,该接口允许获取快照的元数据,但不能获取原始对象的状态。
在这种限制性政策下,纪念品可以存储在其他对象中,通常称为看守者。看守者对纪念品的访问权限有限,因此它无法更改其状态。同样,发起者可以访问备忘录中的所有字段,允许它随意恢复其先前的状态。
在实现撤销时,命令和备忘录设计模式可以一起使用。命令负责对目标对象执行各种操作,而备忘录在命令执行之前记录该对象的状态。
UML 类图
实施步骤
源代码实现
需要时,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 设计模式的优点
如果你喜欢这篇文章,你知道该怎么做
关注七爪网,获取更多APP/小程序/网站源码资源!
| 留言与评论(共有 0 条评论) “” |