Memento Pattern 备忘录模式,可以让我们对某时刻对象的内部状态进行保存、备份,以便日后需要时对其进行恢复、还原
模式思想
我们日常工作、生活中也有很多类似的需求、应用。比如Word文档的撤销功能、玩游戏时的存档功能等。而备忘录模式即是对上述需求、场景、应用的经验总结、理论提炼。具体地,在该模式下有三个角色
- 发起人角色:通常我们将需要进行备份保存内部状态、数据的对象,称之为发起人角色。其支持创建某个时候该角色内部状态的数据备份(即所谓的备忘录)及利用某个数据备份(即所谓的备忘录)来恢复该角色的内部状态。即本文示例的Role游戏角色类
- 备忘录角色:该角色作用在于保存发起人角色的状态、数据。即本文示例的GameArchive游戏存档类
- 负责人角色:该角色提供了对备忘录实例的管理功能。具体地,包括存储、提供备忘录实例等功能。即本文示例的GameArchiveCaretaker游戏存档的负责人类
在运行过程中,发起人根据需要适时创建某个时刻下数据、状态的备份,即创建备忘录角色实例。并将该备忘录实例交由负责人角色进行存储、管理。当需要恢复备份时,则先从负责人角色获取相应的备忘录实例,然后交由发起人角色以用于数据、状态的恢复
实现
现在我们来实现一个游戏存档的小例子,以便大家更好的理解该模式。首先对于一个游戏中的角色而言,其通常具备以下状态:游戏角色名称、关卡名称、生命值、魔法值。与此同时,我们也需要根据该类的状态、数据做备份,即所谓的游戏存档。所以该Role类即为我们的发起人角色。可以看到在该类实现中,我们分别提供了createGameArchive方法、loadGameArchive方法,实现了对游戏过程的存档、读档功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
@Data public class Role {
private String roleName;
private String missionName;
private Integer hp;
private Integer mp;
public Role(String roleName, String missionName, Integer hp, Integer mp) { this.roleName = roleName; this.missionName = missionName; this.hp = hp; this.mp = mp; }
public void getInfo() { String info1 = "游戏状态: <"+ roleName +"> 在 " + missionName; String info2 = " 生命值: " + hp + " 魔法值: " + mp + "\n"; System.out.println(info1); System.out.println(info2); }
public GameArchive createGameArchive() { GameArchive gameArchive = new GameArchive(roleName, missionName, hp, mp); return gameArchive; }
public void loadGameArchive(GameArchive gameArchive) { this.roleName = gameArchive.getRoleName(); this.missionName = gameArchive.getMissionName(); this.hp = gameArchive.getHp(); this.mp = gameArchive.getMp(); } }
|
现在让我们来实现备忘录角色,即所谓的游戏存档GameArchive类。其用于保存游戏过程中某个时刻游戏角色的状态数据。其实现如下所示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
|
@Getter public class GameArchive {
private String roleName;
private String missionName;
private Integer hp;
private Integer mp;
public GameArchive(String roleName, String missionName, Integer hp, Integer mp) { this.roleName = roleName; this.missionName = missionName; this.hp = hp; this.mp = mp; }
}
|
最后,我们来实现负责人角色,即游戏存档负责人GameArchiveCaretaker类。其作用就是提供对游戏存档的管理功能。这里我们通过Map实现了对多个游戏存档的管理功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
|
public class GameArchiveCaretaker {
private Map<String, GameArchive> map = new HashMap<>();
public void addGameArchive(GameArchive gameArchive) { String gameArchiveName = gameArchive.getRoleName() + "-" + gameArchive.getMissionName(); map.put( gameArchiveName, gameArchive ); }
public GameArchive getGameArchive(String gameArchiveName) { GameArchive gameArchive = map.get(gameArchiveName); return gameArchive; }
public void viewGameArhiveNameList() { Set gameArhiveNameList = map.keySet(); String str = "游戏存档列表: " + gameArhiveNameList.toString() + "\n"; System.out.println(str); } }
|
好了,现在让我们来看看该模式是如何运作的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
public class MementoPatternDemo { public static void main(String[] args) { GameArchiveCaretaker gameArchiveCaretaker = new GameArchiveCaretaker(); Role role = new Role("林克", "第一关: 玛雅神庙", 100, 100); role.getInfo(); gameArchiveCaretaker.addGameArchive( role.createGameArchive() );
role.setMissionName("第二关: 雷电圣兽"); role.setHp(90); role.setMp(70); role.getInfo(); gameArchiveCaretaker.addGameArchive( role.createGameArchive() );
gameArchiveCaretaker.viewGameArhiveNameList();
role.setMissionName("第三关: 二河流域"); role.setHp(11); role.setMp(7); role.getInfo();
String gameArchiveName = "林克-第二关: 雷电圣兽"; role.loadGameArchive( gameArchiveCaretaker.getGameArchive(gameArchiveName) ); role.getInfo(); } }
|
测试结果如下,符合预期
参考文献
- Head First 设计模式 弗里曼著