今天要向大家介绍的模式是备忘录模式,有时又称作快照模式。
这个备忘录模式一个典型的应用场景就是游戏存档。有时候为了打Boss,没有成功,反而被Boss打死了,这个时候就需要利用我们之前的存档回到最接近Boss的那一关再继续。
备忘录模式的定义如下:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在改对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态。——《大话设计模式》
从这个定义我们不难看出,备忘录模式最大的一个特点就是将某一个对象的状态保存到了这个对象的外部,而不是在客户端频繁调用get和set方法,这样,就减轻了客户端的负担,同时对数据提供了更好的屏蔽性。
备忘录模式的UML类图如下:
Originator类是一个发起人,就好比游戏中的某一个场景(Scene),它除了自己的属性之外还有两个方法,一个是CreateMemento方法,用于创建备忘录/快照,还有一个是setMemento方法,用于恢复备忘录/快照。
Memento类就是备忘录模式的核心,备忘录类(或者称快照类)了,这个类中保存了我们需要Originator存档的属性,并提供get方法。
Caretaker类是管理者,用于管理备忘录,它维护Memento类对象,并提供其get和set方法,它并不能Memento类内部成员。(管理者嘛,重点在维护,而不需要知道其中的奥秘~)
值得一提的是,有时候我们并不一定要在备忘录中存储一个类对象的全部内容,只需存储部分,这个模式同样可以胜任~
下面将游戏存档的场景用备忘录模式模拟出来:
UML类图:
其中,GameRole类就是Originator,Administrator就是Caretaker,Memento类与上边对应。
转换成代码如下:
import java.util.*;
//游戏角色(发起人类)
class GameRole
{
//角色名称
private String name;
//角色力量
private double power;
//角色血量
private double blood;
public GameRole(String name , double power , double blood)
{
this.name = name;
this.power = power;
this.blood = blood;
}
//打Boss方法,假设打不过Boss,血量将为0
public void fight()
{
System.out.println("=====Start Fifhting=====");
this.blood = 0;
}
public String toString()
{
return "Role Name:"+this.name+"\n Role Power:"+this.power+"\n Role Blood:"+blood;
}
//存档方法,这里我们只需要对血量进行存档
public Memento saveStatus()
{
return new Memento(this.blood);
}
//恢复存档方法
public void setMemento(Memento snapshot)
{
System.out.println("=====Recovering...=====");
this.blood = snapshot.getBlood();
}
}
//备忘录类
class Memento
{
private double blood;
public Memento(double blood)
{
this.blood = blood;
}
public double getBlood()
{
return this.blood;
}
}
//管理者类
class Administrator
{
private Memento memento;
public void setMemento(Memento snapshot)
{
this.memento = snapshot;
}
public Memento getMemento()
{
return this.memento;
}
}
public class Main
{
public static void main(String args[])
{
GameRole gr = new GameRole("XX",100,100);
System.out.println(gr);
Administrator admin = new Administrator();
admin.setMemento(gr.saveStatus());
gr.fight();
System.out.println(gr);
gr.setMemento(admin.getMemento());
System.out.println(gr);
}
}