1.定义
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态。该模式又叫快照模式。
2. 场景
在游戏中碰到BOSS或者临时有事离开前都会选择存档,等到合适的时间可以读档到上次或者前几次保存的位置。
2.1 发起人
控制需要备份的数据,创建和恢复备忘录。它直接和备忘录对象接触,其他对象需要操作备忘录都要经过发起人。
@Data // lombok
public class GameRole {
private Integer level; // 等级
private Integer maxBloodFlow; // 最大血量
private Integer bloodFlow; // 当前血量
private String name; // 角色名
private Integer gold; // 金币
private Integer copper; // 铜币
/**
* 保存备忘录
* @return
*/
public Memento saveMemento() {
return new Memento.Builder().name(name).level(level).gold(gold).copper(copper).maxBloodFlow(maxBloodFlow).build();
}
/**
* 恢复备忘录
* @param memento
*/
public void restoreMemento(Memento memento) {
this.level = memento.getLevel();
this.maxBloodFlow = memento.getMaxBloodFlow();
this.name = memento.getName();
this.gold = memento.getGold();
this.copper = memento.getCopper();
}
// 建造者模式
public static class Builder{
private GameRole gameRole;
Builder() {
gameRole = new GameRole();
}
public Builder level(Integer level) {
gameRole.setLevel(level);
return this;
}
public Builder maxBloodFlow(Integer maxBloodFlow) {
gameRole.setMaxBloodFlow(maxBloodFlow);
return this;
}
public Builder bloodFlow(Integer bloodFlow){
gameRole.setBloodFlow(bloodFlow);
return this;
}
public Builder name(String name) {
gameRole.setName(name);
return this;
}
public Builder gold(Integer gold) {
gameRole.setGold(gold);
return this;
}
public Builder copper(Integer copper) {
gameRole.setCopper(copper);
return this;
}
public GameRole build() {
return gameRole;
}
}
}
这里在备忘录中少了一个属性bloodFlow,为了模拟游戏中重新读档之后当前的血量清空的情况,同时也说明备忘录的属性和发起人的属性不一定要一样。
备忘录
负责存储发起人对象的内部状态,它的出现是应该发起人的需要。
@Data
public class GameRole {
private Integer level; // 等级
private Integer maxBloodFlow; // 最大血量
private Integer bloodFlow; // 当前血量
private String name; // 角色名
private Integer gold; // 金币
private Integer copper; // 铜币
/**
* 保存备忘录
* @return
*/
public Memento saveMemento() {
return new Memento.Builder().name(name).level(level).gold(gold).copper(copper).maxBloodFlow(maxBloodFlow).build();
}
/**
* 恢复备忘录
* @param memento
*/
public void restoreMemento(Memento memento) {
this.level = memento.getLevel();
this.maxBloodFlow = memento.getMaxBloodFlow();
this.name = memento.getName();
this.gold = memento.getGold();
this.copper = memento.getCopper();
}
public static class Builder{
private GameRole gameRole;
Builder() {
gameRole = new GameRole();
}
public Builder level(Integer level) {
gameRole.setLevel(level);
return this;
}
public Builder maxBloodFlow(Integer maxBloodFlow) {
gameRole.setMaxBloodFlow(maxBloodFlow);
return this;
}
public Builder bloodFlow(Integer bloodFlow){
gameRole.setBloodFlow(bloodFlow);
return this;
}
public Builder name(String name) {
gameRole.setName(name);
return this;
}
public Builder gold(Integer gold) {
gameRole.setGold(gold);
return this;
}
public Builder copper(Integer copper) {
gameRole.setCopper(copper);
return this;
}
public GameRole build() {
return gameRole;
}
}
}
2.3 负责人
对备忘录进行管理,保存和提供备忘录。虽然都有保存和提供备忘录的功能,但是区别于发起人的地方是:发起人的操作一般比较固定,就是提供保存和恢复功能,而负责人可以实现恢复最近的或者某个之前的备忘录或者保存多个备忘录的功能。
/**
* 负责人
*/
public class MementoCaretaker {
private Map<String, Memento> mementoMap = new HashMap<>();
public Memento getMemento(String tag){
return mementoMap.get(tag);
}
public void setMemento(String tag, Memento memento){
this.mementoMap.put(tag, memento);
}
}
2.4 测试
public class TestMemento {
public static void main(String[] args) {
// 当前游戏角色状态
GameRole.Builder builder = new GameRole.Builder();
GameRole gameRole = builder.name("张三").bloodFlow(456).maxBloodFlow(1000).level(10).gold(10000).copper(123).build();
// 存档----
MementoCaretaker mementoCaretaker = new MementoCaretaker();
mementoCaretaker.setMemento("0001", gameRole.saveMemento());
// 模拟打BOSS前等级以及金币等变化
gameRole.setLevel(11);
gameRole.setBloodFlow(300);
gameRole.setGold(5000);
gameRole.setCopper(300);
System.out.println(gameRole);
// 读档
Memento memento = mementoCaretaker.getMemento("0001");
gameRole.restoreMemento(memento);
System.out.println(gameRole);
}
}
----------------------------console
GameRole(level=11, maxBloodFlow=1000, bloodFlow=300, name=张三, gold=5000, copper=300)
GameRole(level=10, maxBloodFlow=1000, bloodFlow=300, name=张三, gold=10000, copper=123)