备忘录模式(Momento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。又叫快照模式。
备忘录模式是一个比较简单的模式,用于备份对象状态。通常可以与命令模式等一起使用。
备忘录模式有三个角色:备忘录(Memento)角色,发起人(Originator)角色,负责人(Caretaker)角色。
从类图上可以看出,发起人和备忘录角色都有 state 属性,其实可以把备忘录角色当作发起人角色的属性容器,发起人决定要备份哪些状态,并将状态放到备忘录中,备忘录存储这些状态,并且可以被保存起来,在需要的时候提供给发起人用于恢复到以前。
我们结合命令模式来说明备忘录模式,依然使用浏览器的返回场景来说明。用户在浏览器中点击某个超链接跳到另一个页面,点击返回回到上一个链接页面,我们将点击抽象成命令,将返回抽象成恢复状态,浏览器就是我们的发起人角色。
/**
* 在浏览器中是URL跳转
*/
public interface Command<T> {
void execute(T param);
void back();
}
@Data
public class Memento {
private String url;
}
// 浏览器窗口
public class Window {
private String url;
public Memento createMemento() {
Memento m = new Memento();
m.setUrl(this.url);
return m;
}
public void restoreMemento(Memento m) {
rendUrlAndShow(m.getUrl());
}
public void rendUrlAndShow(String url) {
this.url = url;
System.out.println(url);
}
}
public class UrlCommand implements Command<String> {
private Window window;
private Memento m;
public void execute(String url) {
this.m = window.createMemento();
window.rendUrlAndShow(url);
}
public void back() {
// 将原窗口再设置回去
window.restoreMemento(m);
}
}
public class User {
public static void main(String[] args) {
// 在浏览器里用户点击 a.com
String url = "www.a.com";
Command<String> commandA = new UrlCommand();
commandA.execute(url);
// 用户点击返回
stack.pop().back();
}
}
在这里 UrlCommand
既是 命令模式中的Command
角色也是备忘录模式中的 负责人
角色。
Stack
等数据结构使用,例如浏览器支持多次返回,例子如下:
public class User {
public static void main(String[] args) {
Stack<String> stack = new Stack<>();
// 在浏览器里用户点击 a.com
String url = "www.a.com";
Command<String> commandA = new UrlCommand();
commandA.execute(url);
stack.push(commandA);
// 用户点击b.com
url = "www.b.com"
Command<String> commandB = new UrlCommand();
commandB.execute(url);
stack.push(commandB);
// 用户点击返回
stack.pop().back();
// 用户又点击一次返回
stack.pop().back();
}
}