备忘录模式
-
备忘录模式和原型模式:
备忘录模式是保存对象当时的信息 , 而原型模式是调用clone()方法进行对象的克隆 , 所以我认为可以将备忘录模式进行修改 , 保存对象信息可以直接使用clone()克隆对象 , 然后保存到备忘录中 , 但是这就涉及到浅拷贝和深拷贝的问题 , 如果我们的 “发起人类” (Originator) 内部引用类型稍微复杂的话 , 建议不去使用clone()方法 , 而直接进行信息的保存 .
-
定义:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态 , 这样以后就可以将该对象恢复到原先保存的状态。备忘录模式就像我们大家玩的游戏存档一样 , 当我们打不过BOSS时 , 就可以先保存游戏进度 , 然后再去进行下一步的行动 . 这样方便我们再次从想要的位置开始。
-
使用场景:
- 需要保存一个对象在某一个时刻的状态或部分状态。
- 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性,一个对象不希望外界直接访问其内部状态,通过中间对象可以间接访问其内部状态。
- 浏览器回退、数据库备份和恢复、编辑器撤销和还原、虚拟机生成快照和恢复、Git版本控制、棋牌类游戏悔棋等等。
-
UML:
- Main:它是一个普通类,可以创建一个备忘录,并存储它的当前内部状态,也可以使用备忘录来恢复其内部状态,一般将需要保存内部状态的类设计为原发器。
- Memento:存储原发器的内部状态,根据原发器来决定保存哪些内部状态。备忘录的设计一般可以参考原发器的设计,根据实际需要确定备忘录类中的属性。需要注意的是,除了原发器本身与负责人类之外,备忘录对象不能直接供其他类使用,原发器的设计在不同的编程语言中实现机制会有所不同。
- Gamer:负责人又称为管理者,它负责保存备忘录,但是不能对备忘录的内容进行操作或检查。在负责人类中可以存储一个或多个备忘录对象,它只负责存储对象,而不能修改对象,也无须知道对象的实现细节。
-
优点:
- 它提供了一种状态恢复的实现机制,使得用户可以方便地回到一个特定的历史步骤,当新的状态无效或者存在问题时,可以使用暂时存储起来的备忘录将状态复原。
- 备忘录实现了对信息的封装,一个备忘录对象是一种原发器对象状态的表示,不会被其他代码所改动。备忘录保存了原发器的状态,采用列表、堆栈等集合来存储备忘录对象可以实现多次撤销操作。
-
缺点:
- 资源消耗过大,如果需要保存的原发器类的成员变量太多,就不可避免需要占用大量的存储空间,每保存一次对象的状态都需要消耗一定的系统资源。
-
样例:
/** * 角色备忘录 ; */ public class RoleMemo { private String name ; private String ability ; public RoleMemo(String name , String ability) { this.name = name ; this.ability = ability ; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAbility() { return ability; } public void setAbility(String ability) { this.ability = ability; } }
/** * 角色 ; */ public class Role { private String name ; private String ability ; @Override public String toString() { return "角色:" + this.name + "\n" + "能力:" + this.ability ; } /** * 保存角色 ; * @return */ public RoleMemo saveRole(){ return new RoleMemo(name , ability) ; } /** * 恢复角色 ; * @param roleMemo */ public void recoverRole(RoleMemo roleMemo){ this.name = roleMemo.getName() ; this.ability = roleMemo.getAbility() ; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAbility() { return ability; } public void setAbility(String ability) { this.ability = ability; } }
/** * 备忘录管理者 ; */ public class Caretaker { private RoleMemo roleMemo ; public RoleMemo getRoleMemo() { return roleMemo; } public void setRoleMemo(RoleMemo roleMemo) { this.roleMemo = roleMemo; } }
public class MemoModeDemo { public static void main(String[] args) { Role role = new Role() ; role.setName("钢铁侠"); role.setAbility("操控钢铁"); System.out.println(role.toString()); Caretaker caretaker = new Caretaker() ; caretaker.setRoleMemo(role.saveRole()); role.setName("美国队长"); role.setAbility("使用盾牌"); System.out.println(role.toString()); role.recoverRole(caretaker.getRoleMemo()); System.out.println(role.toString()); } }