备忘录模式是一种行为型设计模式,它允许你在不暴露对象实现细节的情况下,捕获和保存对象的内部状态。之后,可以通过保存的状态将对象恢复到原先的状态。备忘录模式的核心思想是“在不暴露对象的内部实现的情况下,保存对象的状态,并可以随时恢复这个状态”。
简单来说,备忘录模式帮助我们在某一时刻保存对象的状态,以便以后恢复。
一、备忘录模式的结构
备忘录模式由三个角色组成:
- Originator(发起人):负责创建备忘录和使用备忘录来恢复其内部状态。
- Memento(备忘录):备忘录对象包含了 Originator 的内部状态,可以在需要时提供给 Caretaker 使用。备忘录不应该对外暴露其内容。
- Caretaker(管理者):负责保存备忘录的对象,它不关心备忘录的内容,只知道如何保存和恢复备忘录。Caretaker 通常会持有多个备忘录,以便进行不同的状态恢复。
二、工作原理
备忘录模式的工作原理主要包括以下几个步骤:
- 保存状态:当对象的状态发生变化时,发起人对象(Originator)会创建一个备忘录对象(Memento),并将其当前状态存储在备忘录中。
- 恢复状态:当需要恢复对象的状态时,发起人会从管理者对象(Caretaker)处获取对应的备忘录,并使用备忘录中的状态信息恢复自身的状态。
- 管理备忘录:管理者对象(Caretaker)负责保存多个备忘录,并确保每个备忘录对应的对象状态是可以恢复的。
三、备忘录模式的实现示例
白箱备忘录
白箱备忘录模式是指备忘录对象暴露了内部状态的实现细节,管理者类(Caretaker)不仅能够保存和恢复备忘录,还可以直接访问备忘录中的数据。因此,备忘录是白箱的,它对外部类是透明的,管理者类可以直接读取和修改备忘录的内容。
-
发起人类
public class Role {
private int vit = 100;//生命
private int atk = 100;//攻击
private int def = 100;//防御
public void fight(){
this.vit = 0;
}
public Memento saveMemento(){
return new Memento(vit,atk,def);
}
public void recoverMemento(Memento memento){
this.vit = memento.getVit();
this.atk = memento.getAtk();
this.def = memento.getDef();
}
public void display(){
System.out.println("生命力"+vit);
System.out.println("攻击力"+atk);
System.out.println("防御力"+def);
}
}
-
备忘录类
public class Memento {
private int vit;
private int atk;
private int def;
public int getVit() {
return vit;
}
public int getAtk() {
return atk;
}
public int getDef() {
return def;
}
public Memento() {
}
public Memento(int vit, int atk, int def) {
this.vit = vit;
this.atk = atk;
this.def = def;
}
}
-
管理者类
public class RoleStateCaretaker {
private Memento memento;
public void setRoleState(Memento memento){
this.memento = memento;
}
public Memento getRoleState(){
return memento;
}
}
-
使用备忘录模式
public class Client { public static void main(String[] args) { System.out.println("----------大战之前的状态--------"); Role role = new Role(); role.display(); RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setRoleState(role.saveMemento()); System.out.println("----------大战之后的状态--------"); role.fight(); role.display(); System.out.println("----------恢复之前状态--------"); role.recoverMemento(roleStateCaretaker.getRoleState()); role.display(); } }
-
运行结果
黑箱备忘录
黑箱备忘录模式是指备忘录对象完全封装了发起人的状态,外部类(包括管理者类 Caretaker)不能直接访问备忘录中的状态数据。换句话说,备忘录是黑箱的,发起人类是唯一能够读取和修改备忘录内部状态的类。管理者类(Caretaker)只负责保存和恢复备忘录对象,但无法查看备忘录中的数据内容。
针对上述示例,我们定义Memento接口供外部使用,Memento实现类为发起人类的私有内部类
-
发起人类
public class Role { private int vit = 100;//生命 private int atk = 100;//攻击 private int def = 100;//防御 public void fight(){ this.vit = 0; } public Memento saveMemento(){ return new RoleStateMemento(vit,atk,def); } public void recoverMemento(Memento memento){ RoleStateMemento roleStateMemento = (RoleStateMemento) memento; this.vit = roleStateMemento.getVit(); this.atk = roleStateMemento.getAtk(); this.def = roleStateMemento.getDef(); } public void display(){ System.out.println("生命力"+vit); System.out.println("攻击力"+atk); System.out.println("防御力"+def); } private class RoleStateMemento implements Memento { private int vit; private int atk; private int def; public int getVit() { return vit; } public int getAtk() { return atk; } public int getDef() { return def; } public RoleStateMemento(int vit, int atk, int def) { this.vit = vit; this.atk = atk; this.def = def; } } }
-
标记接口
public interface Memento { }
-
管理员类
public class RoleStateCaretaker { private Memento memento; public void setRoleState(Memento memento){ this.memento = memento; } public Memento getRoleState(){ return memento; } }
-
测试类
public class Client { public static void main(String[] args) { System.out.println("----------大战之前的状态--------"); Role role = new Role(); role.display(); RoleStateCaretaker roleStateCaretaker = new RoleStateCaretaker(); roleStateCaretaker.setRoleState(role.saveMemento()); System.out.println("----------大战之后的状态--------"); role.fight(); role.display(); System.out.println("----------恢复之前状态--------"); role.recoverMemento(roleStateCaretaker.getRoleState()); role.display(); } }
-
运行结果
四、备忘录模式的优缺点
优点:
- 封装性好:备忘录模式可以在不暴露对象内部实现细节的情况下,保存和恢复对象的状态,从而保持了封装性。
- 灵活性高:可以随时创建和恢复对象的不同状态,支持“撤销”和“恢复”功能。
- 实现简单:备忘录模式可以通过简单的对象组合实现,逻辑清晰且易于理解。
缺点:
- 内存消耗:如果每次都创建备忘录来保存对象的状态,会导致大量备忘录对象的产生,可能会占用较多内存。
- 复杂性增加:当对象的状态非常复杂时,备忘录的管理可能会变得很复杂,尤其是涉及多个状态的保存与恢复时。
- 可能会泄露实现细节:尽管备忘录对象的设计要求不能暴露状态信息,但在某些情况下,备忘录对象的实现可能会不小心暴露对象的内部状态。
五、适用场景
- 撤销操作:当需要实现操作的撤销功能时,备忘录模式是一个理想的选择。它可以在执行操作前保存状态,以便在撤销时恢复到先前的状态。
- 状态恢复:当需要恢复某一时刻的对象状态时,备忘录模式提供了便捷的解决方案。
- 版本管理:在版本控制系统中,保存每个版本的状态(如文件的内容或数据库的状态),然后可以随时恢复到某个历史版本。