行为设计模式之Memento(备忘录)
行为设计模式之Memento(备忘录)
前言:
备忘录设计模式,有点像vmware快照可以回滚,idea的提交记录同样可以混滚,流程引擎中流程可以撤销到或者回滚到某个指定的状态。
1)意图
在不破坏封装性的前提下捕获一个对象的内部状态,并在对象之外保存这个状态。这样以后就可以将对象恢复到原先保存的状态。
2)结构
3)适用性
Mement 模式适用于:
- 必须保存一个对象在某一个时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
- 如果一个用接口来让其他对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
import java.util.ArrayList;
import java.util.List;/*** @author psd 行为设计模式之备忘录模式*/
public class MementoPatternDemo {public static void main(String[] args) {// 创建管理者Caretaker caretaker = new Caretaker();// 创建原发器Originator originator = new Originator();originator.setState("state1");Memento back1 = originator.createMemento();caretaker.addMemento(back1);originator.setState("state2");Memento back2 = originator.createMemento();caretaker.addMemento(back2);originator.setState("state3");Memento back3 = originator.createMemento();caretaker.addMemento(back3);caretaker.showMemento();System.out.println("--------------------");Memento memento = caretaker.getMemento(2);originator.setState(memento.getState());System.out.println("回滚到第二次备份,还原之后的状态:" + originator.getState());}
}/*** 原发器*/
class Originator{private String state;public void setState(String state) {this.state = state;}public String getState() {return state;}public Memento createMemento(){return new Memento(state);}public void setMemento(Memento memento){this.state = memento.getState();}
}/*** 管理者*/
class Caretaker{private List<Memento> mementoList = new ArrayList<>();public void addMemento(Memento memento){mementoList.add(memento);}public Memento getMemento(int index){if (index >= 0 && index < mementoList.size()){return mementoList.get(index - 1);}return null;}public void showMemento(){int currentIndex = 1;for (Memento memento : mementoList) {System.out.println("第" + currentIndex + "个备忘录的状态为:" + memento.getState());currentIndex++;}}}/*** 备忘录*/
class Memento{private String state;public String getState() {return state;}public void setState(String state) {this.state = state;}public Memento(String state) {this.state = state;}
}
总结:
**备忘录模式(Memento Pattern)**的核心思想是在不破坏对象封装性的前提下,捕获并外部化(存储)一个对象的内部状态,以便以后可以将该对象恢复到原先保存的状态。
它的主要使用场景围绕着需要保存对象状态并在未来某个时刻恢复该状态的需求,同时要求不能直接暴露对象的内部实现细节(封装性原则)。以下是其最典型和常见的应用场景:
撤销/重做操作:
这是最经典的应用场景。 在文本编辑器、图形编辑器、IDE、电子表格、绘图软件等交互式应用中,用户需要能够撤销(Undo)之前的操作,并可能重做(Redo)被撤销的操作。
如何应用: 在执行任何会改变应用状态(如添加文字、移动图形、修改单元格值)的命令之前,创建该状态关键部分的备忘录(Memento)并保存到历史栈中。当用户执行“撤销”操作时,从栈顶弹出最近的备忘录,并用它恢复应用的状态。“重做”则通常使用另一个栈来存储被撤销的操作状态。
游戏存档/读档:
游戏中需要保存玩家的进度(角色位置、生命值、装备、关卡状态等),以便玩家下次可以继续游戏,或者在游戏失败后从检查点(Checkpoint)重新开始。
如何应用: 在玩家手动存档或到达检查点时,创建代表当前游戏状态(由游戏引擎或特定对象管理)的备忘录,并将其序列化存储到文件或数据库中。当玩家选择“加载游戏”时,读取相应的备忘录数据并反序列化,然后用它来恢复游戏引擎的状态。
事务回滚:
在数据库操作或需要原子性的业务流程中,如果一系列操作中的某一步失败,需要将所有操作回滚到事务开始前的状态,以保证数据一致性。
如何应用: 在事务开始时,为参与事务的关键业务对象创建备忘录。如果在事务过程中发生错误,则使用这些备忘录将所有对象恢复到事务开始前的状态。备忘录模式在这里更侧重于内存中业务对象的状态恢复,而数据库本身通常有自己的事务机制(如日志),但原理相通。
状态快照与恢复:
任何需要临时保存对象状态并在之后某个时刻精确恢复到该状态的场景。例如:
算法执行过程中可能需要回溯到之前的某个状态。
在复杂的配置工具中,允许用户保存当前的配置组合作为“快照”,之后可以一键恢复到这个快照配置。
工作流引擎中,保存流程实例在某个节点的状态,以便稍后(如系统重启后)从中断点继续执行。
需要临时修改对象状态进行某些操作,操作完成后需要还原到原始状态。
协作工具中的版本控制(基础原理):
虽然成熟的版本控制系统(如Git)复杂得多,但其核心思想之一也包含了备忘录模式的概念:保存文件或项目在某个时间点的完整状态(快照),允许用户回退到历史版本。备忘录模式为这种“保存状态-恢复状态”的能力提供了基础设计思路。
备忘录模式适用的关键判断点:
需要保存状态: 应用有明确的需求要在某个时间点记录对象的内部状态。
需要恢复状态: 应用有明确的需求要在未来某个时间点将对象恢复到之前保存的状态。
需要保持封装性: 直接暴露对象的所有内部字段来保存状态会破坏对象的封装性,带来维护困难和潜在的错误。备忘录模式通过一个只由原发器(Originator)对象操作的“备忘录”对象来间接存储状态,避免了其他对象直接访问其内部细节。
状态数据量可控: 虽然备忘录可以存储复杂状态,但频繁保存大量状态(如高分辨率图像编辑的每一步)可能导致内存消耗过大。这时可能需要结合增量存储、命令模式存储操作而非全状态、或外部存储(如数据库/文件)等策略进行优化。
总结来说,当你的应用需要实现“时光机”功能(如撤销、存档/读档、回滚、快照恢复),并且你希望以符合面向对象设计原则(特别是封装性)的方式来实现时,备忘录模式就是一个非常合适的选择。 它清晰地分离了状态捕获/恢复的职责(由Originator和Memento负责)和状态历史的存储管理职责(由Caretaker负责)。
喜欢我的文章记得点个在看,或者点赞,持续更新中ing…