备忘录模式(Memento):在不破坏封装性的的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可将该对象恢复到原先保存的对象。
白话:备忘录模式好比游戏中的备份,记录了以前的状态,用于状态出错时恢复使用。
角色:(1)原发器(Originator):需要被备忘存档的对象。
(2)备忘录(Memento):对原发器中状态备份。
(3)备份管理器(CareTaker):管理备忘录,本人理解如果存在多个备忘录时有用。
使用场景:
(1)如果不使用备忘录模式:
游戏角色类GameRole使用示例:class GameRole { private String name; private int force; private int life; private int defence; public GameRole(String name, int force, int life, int defence) { super(); this.name = name; this.force = force; this.life = life; this.defence = defence; } public boolean attack(int damage) { this.life -= damage; return this.life > 0; } private GameRole(GameRole role) { this(role.name, role.force, role.life, role.defence); } public GameRole savaData() { GameRole gameRole = new GameRole(this); return gameRole; } public void restoreData(GameRole gameRole) { this.name = gameRole.name; this.force = gameRole.force; this.life = gameRole.life; this.defence = gameRole.defence; }
public class Game { public static void main(String[] args) { GameRole role = new GameRole("lixiaoyao", 10, 100, 20); GameRole saveRoleData = role.savaData(); boolean isSuccess = role.attack(100); if (!isSuccess) { } role.restoreData(saveRoleData); } }
可以看到GameRole用自己给自己做备份,这好像可行,但实际过程中我们备份的往往只是部分状态而非所有的,比如GameRole中只需要备份life,因此完全的拷贝GameRole往往造成浪费,因此可以独立一个专门备份的类,用于保存GameRole的部分数据。(2)使用备忘录类,未使用备忘录管理者
备忘录类:
class RoleMemento { private int life; public RoleMemento() { } public int getLife() { return life; } public void setLife(int life) { this.life = life; } }
更改后的Game类:
class GameRole { private String name; private int force; private int life; private int defence; public GameRole(String name, int force, int life, int defence) { super(); this.name = name; this.force = force; this.life = life; this.defence = defence; } public boolean attack(int damage) { this.life -= damage; return this.life > 0; } public RoleMemento savaData() { RoleMemento memeto = new RoleMemento(); memeto.setLife(life); return memeto; } public void restoreData(RoleMemento memento) { this.life = memento.getLife(); } }
使用示例:public class Game { public static void main(String[] args) { GameRole role = new GameRole("lixiaoyao", 10, 100, 20); RoleMemento saveRoleData = role.savaData(); boolean isSuccess = role.attack(100); if (!isSuccess) { role.restoreData(saveRoleData); } } }
上面没有用到备忘录管理者,其实这个问题一直很疑惑,原发器只需要跟备忘录交互就行了,备忘录管理者来搅什么局,依照本人所见,如果有多个备份的话,可能就需要用到备份管理者,比如上面我只是备份了角色的生命,但游戏中往往还要备份地图,因此还要增加一个地图备份,而地图备份与角色又应该绑在一起,因此用备忘录管理者可以很好的封装这两个对象。(3)使用备份管理类的备份录模式:
新的需要备份的类Map和对应备份类MapMemento
class Map { private String mapName; private int mapProgress; public Map(String mapName, int mapProgress) { super(); this.mapName = mapName; this.mapProgress = mapProgress; } public MapMemento savaData() { MapMemento memeto = new MapMemento(); memeto.setMapName(mapName); memeto.setMapProgress(mapProgress); return memeto; } public void restoreData(MapMemento memento) { this.mapName = memento.getMapName(); this.mapProgress = memento.getMapProgress(); } }
备份录管理类:class MapMemento { private String mapName; private int mapProgress; public String getMapName() { return mapName; } public void setMapName(String mapName) { this.mapName = mapName; } public int getMapProgress() { return mapProgress; } public void setMapProgress(int mapProgress) { this.mapProgress = mapProgress; } public MapMemento() { super(); } }
class GameTaker { private MapMemento mapMento; private RoleMemento roleMento; public MapMemento getMapMento() { return mapMento; } public void setMapMento(MapMemento mapMento) { this.mapMento = mapMento; } public RoleMemento getRoleMento() { return roleMento; } public void setRoleMento(RoleMemento roleMento) { this.roleMento = roleMento; } }
使用示例:public class Game { public static void main(String[] args) { GameRole role = new GameRole("lixiaoyao", 10, 100, 20); Map map = new Map("dota6.81", 50); GameTaker taker = new GameTaker(); taker.setRoleMento(role.savaData()); taker.setMapMento(map.savaData()); boolean isSuccess = role.attack(100); if (!isSuccess) { role.restoreData(taker.getRoleMento()); map.restoreData(taker.getMapMento());; } } }
注:
(1)GameTaker保存了两个备份录,GameTaker只存取备份录,并不对其做改变。
(2)原发器只负责读取,备份的工作交给备份录,简化了原发器的流程。