一 . 模式动机
- 让软件系统可以回到误操作以前,就相当于撤销上一步。备忘录模式就是为了实现这个功能的模式。
- 因此我们需要记录一个对象的内部状态,在具体实现过程中,需要实现备份点和撤销机制,必须事先将状态保存起来。
二 . 模式定义
- 备忘录模式(Memento Pattern):在不破坏封装的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样可以在以后将对象恢复到原先保存的状态。它是一种对象行为模式。
三 . 模式结构
(图片来源于网络)
- Originator:原发器
- Memento:备忘录
- Caretaker:负责人
四 . 模式实列
- 我们做一个简单的备忘录模式实例,就是回到误操作的前一步,记录三个变量用户,密码和电话。
- UML图
- Originator原发器
public class UserInfoDTO {
private String account;
private String password;
private String telNo;
public UserInfoDTO(String account, String password, String telNo) {
this.account = account;
this.password = password;
this.telNo = telNo;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTelNo() {
return telNo;
}
public void setTelNo(String telNo) {
this.telNo = telNo;
}
public Memento saveMemento(){
return new Memento(account,password,telNo);
}
public void restoreMemento(Memento memento){
this.account = memento.getAccount();
this.password = memento.getPassword();
this.telNo = memento.getTelNo();
}
public void show(){
System.out.println("account:"+this.account);
System.out.println("password:"+this.password);
System.out.println("telNo:"+this.telNo);
}
}
- 备忘录
public class Memento {
private String account;
private String password;
private String telNo;
public Memento(String account, String password, String telNo) {
this.account = account;
this.password = password;
this.telNo = telNo;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getTelNo() {
return telNo;
}
public void setTelNo(String telNo) {
this.telNo = telNo;
}
}
- Caretaker负责人
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
- 测试类
public class Client {
public static void main(String[] args) {
UserInfoDTO user = new UserInfoDTO("唐楠","123456","18049453816");
Caretaker caretaker = new Caretaker();
//将状态存储在Caretaker里
caretaker.setMemento(user.saveMemento());
System.out.println("被篡改后:");
user.setAccount("asdsdqwd");
user.setPassword("111111111");
user.setTelNo("dsadqwe12321");
user.show();
//在Caretaker里找到之前存储的旧状态并撤销到旧的状态
System.out.println("恢复后:");
user.restoreMemento(caretaker.getMemento());
user.show();
}
}
- 测试结果
E:\Java\jdk1.8.0_171\bin\java.exe "-javaagent:E:\idea\IntelliJ IDEA 2019.1.3\lib\idea_rt.jar=57942:E:\idea\IntelliJ IDEA 2019.1.3\bin" -Dfile.encoding=UTF-8 -classpath "E:\Java\jdk1.8.0_171\jre\lib\charsets.jar;E:\Java\jdk1.8.0_171\jre\lib\deploy.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;E:\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;E:\Java\jdk1.8.0_171\jre\lib\javaws.jar;E:\Java\jdk1.8.0_171\jre\lib\jce.jar;E:\Java\jdk1.8.0_171\jre\lib\jfr.jar;E:\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;E:\Java\jdk1.8.0_171\jre\lib\jsse.jar;E:\Java\jdk1.8.0_171\jre\lib\management-agent.jar;E:\Java\jdk1.8.0_171\jre\lib\plugin.jar;E:\Java\jdk1.8.0_171\jre\lib\resources.jar;E:\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Design pattern\out\production\Design pattern" Memento备忘录模式.Client
被篡改后:
account:asdsdqwd
password:111111111
telNo:dsadqwe12321
恢复后:
account:唐楠
password:123456
telNo:18049453816
Process finished with exit code 0
五 . 模式分析
- 由于备忘录中存储的是原发器的中间状态,因此需要防止原发器意外的其他对象访问备忘。
- 对于原发起,可以调用备忘录所有信息,允许原发器访问返回先前
六 . 模式优缺点
- 优点
- 提供一种状态恢复的实现机制,使得用户可以方便的回到一个特点的历史步骤。
- 实现了信息的封装
- 缺点
- 资源消耗过大,如果类的成员变量太多,就不可避免占用大量内存,并且每次保存状态都需要消耗内存,因此编辑软件不可能无限制的撤销。
七 . 适用环境和应用
- 适用环境
- 保存一个对象的在某一时刻的状态
- 如果一个接口让其他对象得到这些状态,这将会暴露对象的实现细节并且破坏对象的封装性,一个对象不希望外交直接访问内部状态,通过负责人可以间接访问其内部状态。
- 应用
- 几乎所有的文字或图片编辑软件都提供了撤销功能。
的撤销。
- 几乎所有的文字或图片编辑软件都提供了撤销功能。