文章目录
备忘录模式
备忘录模式(Memento Pattern)又称为快照(Snapshot)模式或Token模式。
备忘录模式就像我们在生活中使用的"后悔药"。有时候,我们可能会做出一些决定或操作,但事后可能会后悔,希望回到之前的状态。备忘录模式就是这样一种"后悔药",它能够帮助我们在需要的时候,返回到之前的状态。比如,在写文档时,如果我们不小心删除了一个重要的段落,使用备忘录模式,我们就可以轻松地恢复到删除之前的状态。但是,这种"后悔药"也有副作用,那就是它可能会占用一些资源,就像我们需要空间来保存这些后悔的机会一样。
定义
英文原话
Without violating encapsulation,capture and externalizean object's internal state so that the object can be restored to this state later.
直译
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。以便之后可以将该对象恢复到原先保存的状态。
如何理解呢?
有时有必要记录一个对象的内部状态。
为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制,而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到他们先前的状态。
但是对象通常封装了其部分或所有的状态信息,使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态。
而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
我们可以用备忘录(Memento)模式解决这一问题。
一个备忘录(memento)是一个对象,他存储另一个对象 (原发器originator)在某个瞬间的内部状态,而后者称为备忘录的原发器 (originator)。
当需要设置原发器的检查点时,备份机制向原发器请求一个备忘录。
原发器 用描述当前状态 的信息初始化 该备忘录。
只有原发器(originator)可以向备忘录中存取信息,备忘录对其他的对象不可见。
适用于 :必须保存一个对象在某一时刻的(部分)状态(以便以后有需要可以恢复回此状态) ;且如果用接口让其他对象直接得到这些状态,将会暴露对象实现细节并破坏对象的封装性。在这样的场景下使用备忘录(Memento)模式。
3个角色
1. Memento(备忘录)
负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。
备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象;而Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
2. Originator(原发器)
originator
创建一个备忘录,用以记录当前时刻它的内部状态。
使用备忘录回复内部状态。
只有创建备忘录的原发器会对他的状态状态进行赋值和检索。
3. Caretaker(负责人)
负责保存好备忘录。
不能对备忘录的内容进行操作或检查。
负责保存与提供备忘录对象,但是不能对备忘录的内容进行访问或者操作。
类图
代码示例
java
package com.polaris.designpattern.list3.behavioral.pattern08.memento.classicdemo;
// 备忘录接口
interface Memento {
// 可能包含一些用于获取状态的方法
String getState();
}
// 发起人(Originator)
class Originator {
private String state;
// 创建一个备忘录并保存当前状态
public Memento createMemento() {
return new MementoImpl(state);
}
// 恢复发起人状态
public void restoreMemento(Memento memento) {
this.state = ((MementoImpl) memento).getState();
}
// 设置发起人状态
public void setState(String state) {
this.state = state;
}
// 获取发起人状态
public String getState() {
return state;
}
// 备忘录实现类,仅供发起人使用
private static class MementoImpl implements Memento {
private String state;
public MementoImpl(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
}
// 管理者(Caretaker)
class Caretaker {
private Memento memento;
// 保存备忘录
public void setMemento(Memento memento) {
this.memento = memento;
}
// 获取备忘录
public Memento getMemento() {
return memento;
}
}
// 使用示例
public class MementoPatternDemo {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State #1");
System.out.println("Current State: " + originator.getState());
// 保存当前状态
caretaker.setMemento(originator.createMemento());
originator.setState("State #2");
System.out.println("Current State: " + originator.getState());
// 恢复之前的状态
originator.restoreMemento(caretaker.getMemento());
System.out.println("Restored State: " + originator.getState());
}
}
/* Output:
Current State: State #1
Current State: State #2
Restored State: State #1
*///~
在这个例子中,
Originator
类维护了一个内部状态state
,并提供了创建备忘录(createMemento
)和恢复状态(restoreMemento
)的方法。备忘录的实际实现是MementoImpl
类,但它被声明为Originator
的私有内部类,因此外部类(如Caretaker
)不能直接访问它。Caretaker
类负责管理备忘录对象。在MemontoPatternDemo
类中,我们展示了如何使用这些类来保存和恢复Originator
的状态。
备忘录模式的应用
备忘录模式,又称之为快照模式(Snapshot Pattern),是一种软件设计模式,主要用于保存和恢复对象的内部状态。以下是其主要应用:
- 撤销和恢复功能:在Word、PhotoShop等软件中,用户可以撤销之前的操作,或恢复到某个历史状态。备忘录模式能够记录用户的每一步操作,从而实现这一功能。
- 电子书的阅读进度:用户在阅读电子书时,可以随时保存阅读进度,下次打开时可以从上次的阅读进度继续阅读。
- 软件开发中的版本控制:记录每个版本的代码快照,方便进行版本控制和回溯。
- 事务管理:在数据库事务处理中,如果一系列操作不能全部完成,就需要回滚操作,将数据恢复到操作之前的状态。备忘录模式可以记录一系列操作的快照,当需要回滚时,可以恢复到备忘录状态。
备忘录模式的优点
- 提供恢复机制:为用户提供一种可以恢复状态的机制,允许在必要时将对象恢复到之前的状态。
- 实现内部状态的封装:除了创建它的发起人之外,其他对象都不能够访问这些状态信息,这有助于保持封装的边界。
- 简化发起人类:发起人不需要管理和保存其内部状态的各个备份,所有状态信息都保存在备忘录中,并由管理者进行管理,这符合单一职责原则。
备忘录模式的缺点
- 资源消耗大:如果要保存的内部状态信息过多或者特别频繁,将会占用比较大的内存资源。
- 难以预测存储需求:当负责人角色将一个备忘录存储起来的时候,可能无法预测这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。
备忘录模式的使用场景
备忘录模式适用于需要保存/恢复数据的相关业务场景,如:
- 撤销操作:在文本编辑器、图形编辑器等工具中,用户可能需要撤销之前的操作。
- 游戏存档:在游戏中,玩家可能需要存档以便在之后恢复游戏进度。
- 数据库事务管理:在数据库事务处理中,如果一系列操作不能全部完成,就需要回滚操作,将数据恢复到操作之前的状态。