1. 备忘录模式概述
备忘录模式保存一个对象的某个状态,以便在适当的时候恢复对象。
一般来说,在备忘录模式中有三个角色:
- Memento:备忘录 —— 包含了对象的状态。
- Originator:发起者 —— 用来根据备忘录中的记录,保存或恢复对象的状态
- Caretaker:管理员 —— 用来增加或者获取备忘录中的记录
也就是说,创建备忘录时,先由Originator对象创建Memento对象,再由Caretaker对象保存Memento对象。而读取备忘录时,先由Caretable对象获取Memento对象,再由Originator对象读取Memento中的信息。
(1) 适用情况
在需要支持用户取消操作时,可以使用备忘录模式。
(2) 优点
可以实现状态恢复,实现回滚操作。
(3) 缺点
每次保存都会创建一个备忘录对象,消耗资源。
2. 备忘录模式实例
使用备忘录模式来实现下棋的过程,提供最基础的下棋、悔棋和重做的功能。
(1) 创建备忘录
public class Memento {
// 记录是什么棋子
private String label;
// 记录横坐标
private int x;
// 记录纵坐标
private int y;
public Memento(String label, int x, int y) {
this.label = label;
this.x = x;
this.y = y;
}
public String getLabel() {
return label;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
(2) 创建棋手类
public class ChessPlayer {
// 记录第几步
private int step = -1;
// 记录是什么棋子
private String label;
// 记录横坐标
private int x;
// 记录纵坐标
private int y;
// 记录备忘录
private List<Memento> mementos = new ArrayList<>();
/**
* 保存状态
*/
public void save() {
// 创建新的备忘录并增加到管理者
mementos.add(new Memento(step, label, x, y));
}
/**
* 恢复状态
*/
public void restore() {
Memento memento = mementos.get(this.step);
this.label = memento.getLabel();
this.x = memento.getX();
this.y = memento.getY();
}
/**
* 显示状态
*/
public void show() {
System.out.printf("棋子<%s>:当前位置:<%d, %d>%n", label, x, y);
}
/**
* 下棋
*/
public void play(String label, int x, int y) {
// 修改棋子状态
this.step++;
this.label = label;
this.x = x;
this.y = y;
// 记录到备忘录
save();
// 显示当前棋子状态
show();
}
/**
* 悔棋,状态恢复到备忘录中的前一个状态
*/
public void undo() {
System.out.println("*****悔棋*****");
this.step--;
// 获取备忘录的前一个状态
restore();
// 显示当前棋子状态
show();
}
/**
* 重做,状态恢复到备忘录中的后一个状态
*/
public void redo() {
System.out.println("*****重做*****");
this.step++;
// 获取备忘录的后一个状态
restore();
// 显示当前棋子状态
show();
}
}
(3) 下棋
public class MementoDemo {
public static void main(String[] args) {
// 创建棋手
ChessPlayer player = new ChessPlayer();
player.play("车", 1, 1);
player.play("车", 1, 5);
player.undo();
player.redo();
}
}
运行结果:
3. 一些思考
在我一开始学习备忘录模式时,我是有些困扰的:为什么要区分发起者和管理员呢?感觉有些多此一举。
于是在上边的例子中,我把发起者和管理员合一了,都由棋手类来完成,发现也能得到相同的结果。
后来,我思考了一下,如果把二者合一,似乎有些违背了单一职责原则。比如,对于棋手来说,他其实只关心下棋、悔棋和重做三个功能,而记录和获取备忘录不应该是它所考虑的。所以,把管理员单独作为一类,似乎是更好的选择,只不过需要更多的代码,这点就见仁见智吧。
参考引用
备忘录模式:www.runoob.com/design-patt…
备忘录模式及典型应用:blog.csdn.net/wwwdc1012/a…