继续整理记录这段时间来的收获,详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用!
6.11 备忘录模式
6.11.1 定义
又称快照模式,在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存此状态,以便后续需要时将该对象恢复到原先保存的状态
6.11.2 结构
- 发起人角色(originator):记录当前时刻的内部状态信息,提供创备忘录和恢复备忘录数据的功能,实现其他业务功能,可以访问备忘录里的所有信息
- 备忘录角色(memento):负责存储发起人的内部状态,在需要的时候提供这些内部状态给发起人
- 管理者角色(Caretaker):对备忘录进行管理,提供保存与获取备忘录的功能,但其不能对备忘录内容进行访问与修改
- 两个等效接口:
- 窄接口:管理对象(和发起人对象之外的任何对象)看到的是备忘录的窄接口(narrow interface),此接口仅仅运行它把备忘录对象传给其他对象
- 宽接口:发起人可以看到宽接口(wide interface),此接口运行它读取所有的数据,以便根据这些数据恢复这个发起人对象的内部状态
6.11.3 案例
6.11.3.1 白箱模式
- 特点:对所有对象提供一个宽接口,违反了封闭原则
- 游戏角色
public class GameRole {
// 角色名称
private String name;
// 生命力
private int vita;
// 攻击力
private int attack;
// 防御力
private int defender;
public int getVita() {
return vita;
}
public void setVita(int vita) {
this.vita = vita;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefender() {
return defender;
}
public void setDefender(int defender) {
this.defender = defender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 初始化状态
public void initState(){
this.attack = 100;
this.vita = 100;
this.defender = 100;
}
// 战斗
public void fight(){
this.vita -= 50;
this.attack -= 50;
this.defender -= 50;
}
// 保存状态
public RoleStateMemento saveState(){
return new RoleStateMemento(name,vita,attack,defender);
}
// 恢复角色状态
public void recoverState(RoleStateMemento roleStateMemento){
// 将备忘录对象中数据赋值给角色对象成员
this.vita = roleStateMemento.getVita();
this.attack = roleStateMemento.getAttack();
this.defender = roleStateMemento.getDefender();
}
// 展示角色属性
public void display(){
System.out.println("角色" + name + "属性:");
System.out.println("角色生命力:" + this.vita);
System.out.println("角色攻击力:" + this.attack);
System.out.println("角色防御力:" + this.defender);
}
}
- 备忘录对象
public class RoleStateMemento {
// 角色名称
private String name;
// 生命力
private int vita;
// 攻击力
private int attack;
// 防御力
private int defender;
public int getVita() {
return vita;
}
public void setVita(int vita) {
this.vita = vita;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefender() {
return defender;
}
public void setDefender(int defender) {
this.defender = defender;
}
public String getName() {
return name;
}
public RoleStateMemento(String name, int vita, int attack, int defender) {
this.attack = attack;
this.vita = vita;
this.defender = defender;
this.name = name;
}
public RoleStateMemento() {
}
}
- 备忘录管理对象
public class RoleStateManage {
// 用集合存储备忘录对象
private Map<String,RoleStateMemento> map = new HashMap<String,RoleStateMemento>();
// 添加备忘录对象
public void addRoleStateMemento(RoleStateMemento roleStateMemento){
map.put(roleStateMemento.getName(),roleStateMemento);
}
// 获取备忘录对象
public RoleStateMemento getRoleStateMemento(String name){
return map.get(name);
}
}
- 测试
public static void main(String[] args) {
System.out.println("大战前-----------------------");
// 创建角色
GameRole gameRole = new GameRole();
gameRole.setName("张三");
// 初始化
gameRole.initState();
// 展示
gameRole.display();
// 保存状态
RoleStateMemento roleStateMemento = gameRole.saveState();
RoleStateManage roleStateManage = new RoleStateManage();
roleStateManage.addRoleStateMemento(roleStateMemento);
System.out.println("大战-----------------------");
gameRole.fight();
// 展示
gameRole.display();
System.out.println("大战后-----------------------");
// 恢复状态
roleStateMemento = roleStateManage.getRoleStateMemento("张三");
gameRole.recoverState(roleStateMemento);
// 展示
gameRole.display();
}
-
结果
-
类图
6.11.4.1 黑箱模式
- 改进:对发起任对象提供宽接口,为其它对象提供窄接口。具体是将备忘录对象设置为发起人的内部成员类
- 抽象备忘录接口,供外部访问
public interface Memento {
}
- 游戏角色
public class GameRole {
// 角色名称
private String name;
// 生命力
private int vita;
// 攻击力
private int attack;
// 防御力
private int defender;
public int getVita() {
return vita;
}
public void setVita(int vita) {
this.vita = vita;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefender() {
return defender;
}
public void setDefender(int defender) {
this.defender = defender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// 初始化状态
public void initState(){
this.attack = 100;
this.vita = 100;
this.defender = 100;
}
// 战斗
public void fight(){
this.vita -= 50;
this.attack -= 50;
this.defender -= 50;
}
// 保存状态
public RoleStateMemento saveState(){
return new RoleStateMemento(vita,attack,defender);
}
// 恢复角色状态
public void recoverState(Memento memento){
RoleStateMemento roleStateMemento = (RoleStateMemento) memento;
// 将备忘录对象中数据赋值给角色对象成员
this.vita = roleStateMemento.getVita();
this.attack = roleStateMemento.getAttack();
this.defender = roleStateMemento.getDefender();
}
// 展示角色属性
public void display(){
System.out.println("角色" + name + "属性:");
System.out.println("角色生命力:" + this.vita);
System.out.println("角色攻击力:" + this.attack);
System.out.println("角色防御力:" + this.defender);
}
//备忘录对象
private class RoleStateMemento implements Memento {
// 生命力
private int vita;
// 攻击力
private int attack;
// 防御力
private int defender;
public int getVita() {
return vita;
}
public void setVita(int vita) {
this.vita = vita;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefender() {
return defender;
}
public void setDefender(int defender) {
this.defender = defender;
}
public RoleStateMemento(int vita, int attack, int defender) {
this.attack = attack;
this.vita = vita;
this.defender = defender;
}
}
}
- 管理备忘录对象
public class RoleStateManage {
// 用集合存储备忘录对象
private Map<String, Memento> map = new HashMap<String, Memento>();
// 添加备忘录对象
public void addRoleStateMemento(String name,Memento memento){
map.put(name,memento);
}
// 获取备忘录对象
public Memento getRoleStateMemento(String name){
return map.get(name);
}
}
- 测试
public static void main(String[] args) {
System.out.println("大战前-----------------------");
// 创建角色
GameRole gameRole = new GameRole();
gameRole.setName("张三");
// 初始化
gameRole.initState();
// 展示
gameRole.display();
// 保存状态
Memento roleStateMemento = gameRole.saveState();
RoleStateManage roleStateManage = new RoleStateManage();
roleStateManage.addRoleStateMemento("张三",roleStateMemento);
System.out.println("大战-----------------------");
gameRole.fight();
// 展示
gameRole.display();
System.out.println("大战后-----------------------");
// 恢复状态
Memento memento= roleStateManage.getRoleStateMemento("张三");
gameRole.recoverState(memento);
// 展示
gameRole.display();
}
- 结果不变,同上
- 类图
6.11.4 优缺点
6.11.4.1 优点
- 提供了一种可以恢复状态的机制,当用户需要时能方便的将数据恢复到某个历史的状态
- 实现了内部状态的封装,除了创建它的发起人外,其它对象都不能访问这些状态信息
- 简化了发起人类,发起人不需要管理和保存其内部状态的备份,所有状态信息保存在备忘录,并有管理者进行管理,复合单一职责原则
6.11.4.2 缺点
- 资源消耗大,若保存频繁或内部状态信息过多,会消耗内存
6.11.5 使用场景
- 需要保存和恢复数据的场景,如游戏存档
- 需要提供一个可回滚操作,如记事本,Word等