七爪源码学习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/小程序/网站源码资源!
梦中崆峒山(图片来之网友)我曾经做过一个梦,梦中我来到崆峒山,山上森林茂密,古木参天,大殿林立,紫红色的砾石山崖在太阳的照射下闪闪发光。我站在山顶,慷慨激昂,滔滔不绝,下面听我演讲的人不计其
基本全了,iPhone14再无秘密,全系亮点都在这关注犟牛,不错过每一篇好文。根据海外博主theapplehub的爆料,基于过去两年的市场表现,iPhone系列的mini机型不论在销量,还是口碑上都没有达到公司的预期。今年,苹果公
保姆级NASblack群晖搭建教程在尝鲜或者说安装黑群晖前,你必须要有一台X86的电脑,不管你是闲置的笔记本台式机各种工控小主机也罢,都是可以的。我本期使用这台J1800处理器的小主机,当时在海鲜市场100来块收的
比贫穷更可怕的是无休止的内耗你知道一个从小到大,都生活在父母无休止的争吵环境里有多崩溃吗?我家是农村的,家里一共四个孩子。小时候家里特别穷,日子过得紧巴巴,穿的衣服都是姐姐穿过的,再轮到我们穿,上学的学费都需
老年之后的夫妻生活,一般都是这样的前言老年之后,有些人觉得很幸福,有些人觉得日子很烦躁,还有些人觉得活在这个世界上就没有意义,其实每个人都有不同的生活方式,由于生长在不同的生活环境,可能每个人的想法和感受不一样,因
隔夜水还能喝吗?大部分人的知识盲区一般情况下隔夜水是可以喝的,但一定要在第二天就饮用完,避免再次隔夜。另外,隔夜水的保存也有要求,如果是放置在没有盖子或水垢较多的杯子水壶等容器中,以及灰尘较多闷热的环境中,不建议隔
舌有裂纹,除了是阴虚,还要注意是气虚中医理论大多来自人对自然的思考取象,上观天文中知人情下知地理,如果说齿痕舌是气虚气亏虚,在自然界中就好像是亏气的气球萎缩了,那裂纹舌则像干涸的农田一样干裂。阴虚干裂多是因为阴虚,阴
华为WATCHGT3Pro手表推送2。1。0。327更新IT之家5月7日消息,华为WATCHGT3Pro手表开始推送HarmonyOS2。1。0。327更新,下载包大小为112MB。支持微信支付新增iOS手机支持钱包交通卡和音乐控制功能
桑树条子从小抈桑条从小抈(育),大来抈不直,意思是桑树的枝条要想培直,必须在它嫩小的时候抈,长成粗枝便无法抈动。教育后代更是如此,对于孩子必须从小抓起,方能收到良好的效果。如今的孩子娇生惯养,凡
高钙牛奶不补钙,3岁前千万别给孩子喝,家长别再躺枪了1岁以上的孩子,渐渐实现了从奶粉到牛奶的过渡,每天至少一瓶奶成为不少家庭每日必须完成的KPI。但由于市场上牛奶产品琳琅满目,家长们往往都是凭着感觉买,或者跟着孩子的口味选,选择很明
这种性格的孩子,注定了将来难有出息,希望你家孩子不是这种性格的孩子,注定了将来难有出息,希望你家孩子不是那天闺蜜约我逛街,于是我们就一起带着孩子出去玩,最后来到了一个儿童游乐场,两个孩子都吵着要玩攀岩,结果就看到这样一幕。两个五六岁