备忘录模式
备忘录模式,即保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态。
场景
当我们使用文本编译器记录一些内容时,发现这一步写错了,往往可以使用Ctrl+Z的方式会退到上一个状态,其中运用到的知识就是备忘录模式。
模式结构
- 发起者角色(Originator):负责创建一个备忘录用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态。
- 备忘录角色(Memento):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。
- 管理者角色(CareTake):负责保存好备忘录。
代码
备忘录角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package designMode.Memento;
public class EmpMemento { private String name; private int age; private int salary;
public EmpMemento(Emp emp) { this.name = emp.getName(); this.age = emp.getAge(); this.salary = emp.getSalary(); } }
|
发起者角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Emp { private String name; private int age; private int salary;
public EmpMemento memento() { return new EmpMemento(this); }
public void recovery(EmpMemento empMemento) { this.name = empMemento.getName(); this.age = empMemento.getAge(); this.salary = empMemento.getSalary(); } }
|
管理者角色
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
public class CareTaker { private EmpMemento memento;
public EmpMemento getMemento() { return memento; }
public void setMemento(EmpMemento memento) { this.memento = memento; } }
|
客户端
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Client { public static void main(String[] args) { CareTaker careTaker = new CareTaker();
Emp emp = new Emp("YoungDream", 20, 7800); System.out.println("第一次打印==> " + emp);
careTaker.setMemento(new EmpMemento(emp));
emp.setAge(22); emp.setSalary(8000); System.out.println("第二次打印==> " + emp);
emp.recovery(careTaker.getMemento());
System.out.println("数据恢复后打印==> " + emp);
} }
|
控制台
1 2 3
| 第一次打印==> Emp{name='YoungDream', age=20, salary=7800} 第二次打印==> Emp{name='YoungDream', age=22, salary=8000} 数据恢复后打印==> Emp{name='YoungDream', age=20, salary=7800}
|
总结
优点
- 备忘录模式可以把发起者内部信息对象屏蔽起来,从而可以保持封装的边界。
- 简化了发起者类。当发起者角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
缺点
- 如果状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象比较昂贵。
- 当发起者对象的状态改变的时候,有可能这个协议无效。如果状态改变的成功率达不到要求,可以考虑采取“假如”协议模式。
当备份点较多时
- 设置栈将备忘点压栈
- 将多个备忘录对象持久化和序列化保存到本地
常见场景
- 数据库事务管理中的回滚操作
- 文本编辑器中的
Ctrl
+z
回退操作