备忘录模式
一 概述
什么是备忘录模式
- 概念:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原来保存的状态。
- 什么意思呢,举个例子简单明了,大家都玩游戏,玩过单机游戏的都知道有一个保存的选项,在你玩到当前关卡时保存,在后面的关卡玩崩了就回到当前的状态继续玩。这就是备忘录模式。
模式的角色
- 原发者:需要在某个时刻保存其状态的对象,原发者负责创建备忘录,使用备忘录保存自己的状态,当原发者需要恢复状态时会通过相应备忘录中的数据恢复当时的状态。
- 备忘录:负责存储原发者状态的对象
- 负责人:也可以称为备忘录管理者,负责保管备忘录对象。
备忘录模式的关键点
- 备忘录模式要求原发者可以访问备忘录中的细节,即可以访问备忘录中的数据,而负责人只能保存和得到备忘录,但访问备忘录中的数据要受到一定的限制。
- 备忘录模式使原发者可以将自己的状态暴露给备忘录,但其他对象想要获得备忘录中的数据要受到一定的限制。这样就保证了原发者暴露内部数据的同时,又保证了数据的封装性。
二 模式的具体实现
模式的设计
我们就按上面的例子进行设计,通过备忘录的关键点,我将备忘录抽象成了一个空的抽象类,将备忘录的实现类设计成了原发者的私有内部类,这样,负责人只能操作接口,并且在操作接口的同时没有可以调用的方法,这样就避免了负责人也能获取到数据。
具体实现
- 备忘录的接口:
public interface IMemento {
}
- 原发者一:利用HashMap 存储状态
public class UserOne {
//保存当前状态
private HashMap<String,String> state;
public UserOne(){
state = new HashMap<>();
}
//保存当前对象的状态
public IMemento createMemento(){
return new Memento(state);
}
//获取保存的对象
public void getMemento(IMemento memento){
state = ((Memento)memento).getState();
}
public void showState(){
System.out.println("现在的状态是:" + state.toString());
}
//进行测试的数据1
public void testState1(){
state.put("关卡", "第一关");
state.put("血量", "100");
state.put("敌人", "0");
}
//进行测试的数据2
public void testState2(){
state.put("关卡", "第二关");
state.put("血量", "0");
state.put("敌人", "11");
}
//同过内部类来进行备忘录的创建,保证信息的安全
private class Memento implements IMemento{
//通过HashMap进行数据的保存
private HashMap<String,String> state;
//对数据进行保存
private Memento(HashMap state){
//这里的state只能new 不能适用this.state = state
//因为会与上面保存当前对象的HashMap指向同一块内存,起不到保存状态的功能
this.state = new HashMap<>(state);
}
private void setState(HashMap state){
this.state = state;
}
private HashMap getState(){
return state;
}
}
}
- 原发者二:利用ArrayList 存储状态
public class UserTwo {
//存放当前状态
private ArrayList<String> state;
public UserTwo(){
state = new ArrayList<>();
}
//创建备忘录,保存此时状态
public IMemento createMemento(){
return new Memento(state);
}
//调用备忘录,回复当时状态
public void getMemento(IMemento memento){
state = ((Memento)memento).getState();
}
public void showState(){
System.out.println("当前状态"+ state.toString());
}
//测试数据1
public void testState1(){
state = new ArrayList<>();
state.add("关卡:第三关");
state.add("血量:50");
state.add("敌人:0");
}
//测试数据二
public void testState2(){
state = new ArrayList<>();
state.add("关卡:第四关");
state.add("血量:0");
state.add("敌人:8");
}
private class Memento implements IMemento{
//存放需要保存的状态
private ArrayList<String> state;
private Memento(ArrayList state){
this.state = new ArrayList<>(state);
}
private void setState(ArrayList state){
this.state = state;
}
private ArrayList getState(){
return state;
}
}
}
- 负责人
/*
* 负责人,负责管理存放的备忘录,
*/
public class CareTaker {
private HashMap<String,IMemento> imemento;
public CareTaker(){
this.imemento = new HashMap<>();
}
//保存备份
public void saveMementos(String name,IMemento memento){
imemento.put(name, memento);
}
//获取备份
public IMemento getMemento(String name){
if(imemento.get(name)!=null){
return imemento.get(name);
}else{
throw new RuntimeException("没有备份");
}
}
}
- 主函数
public class MainClass {
public static void main(String[] args) {
//创建备忘录管理员
CareTaker ck = new CareTaker();
System.out.println("======= 玩家一 ==========");
UserOne us1 = new UserOne();
us1.testState1();
us1.showState();
//保存此时的状态
IMemento m1 = us1.createMemento();
//将备忘录交给管理员
ck.saveMementos("user1", m1);
us1.testState2();
us1.showState();
//获取备忘录
us1.getMemento(ck.getMemento("user1"));
us1.showState();
System.out.println("======= 玩家二 ==========");
UserTwo us2 = new UserTwo();
us2.testState1();
us2.showState();
//保存此时的状态
IMemento m2 = us2.createMemento();
//将备忘录交给管理员
ck.saveMementos("user2", m2);
us2.testState2();
us2.showState();
//获取备忘录
us2.getMemento(ck.getMemento("user2"));
us2.showState();
}
}
- 结果
模式的优点与适用场景
优点
- 备忘录模式适用备忘录可以将原发者的内部状态保存起来,使只有很亲密的对象可以访问备忘录中的数据
- 备忘录模式强调了类设计单一责任原则,即将状态的刻画和保存分开
适用场景
- 必须保存一个对象在某一时刻的全部或部分状态,以便在需要时恢复该对象先前的状态
- 一个对象不想通过public权限的方法让其他对象获取到自己的内部状态。
注:如果备忘录需要存储大量的数据或者非常频繁的创建备忘录,会造成很大的存储开销
这就是我所理解的备忘录,如果我有什么错误或者你有更好的想法,请你告诉我。