[工作中的设计模式]备忘录模式memento
一、模式解析
备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏封装的条件下,将一个对象的状态捕捉(Capture)住,并外部化,存储起来,从而可以在将来合适的时候把这个对象还原到存储起来的状态。备忘录模式常常与命令模式和迭代子模式一同使用。
备忘录模式可以根据客户指令,将相应的对象特有属性进行快照,如果客户要恢复对象,则根据快照提供的特有属性进行还原。
二、模式代码
package memento.patten; /** *备忘录类,同时指定要保存的对象属性 * @author zjl * @time 2016-2-1 * 备忘录:仅有一个状态需要保存 * @author zjl * @time 2016-2-1 * */ public class Memento { private String state; public Memento(String state){ this.state=state; } public String getState() { return state; } public void setState(String state) { this.state = state; } }
2、发起者决定备忘录的属性,已经生成备忘录和还原备忘录的方法
package memento.patten; public class Originator { public String state; public String getState() { return state; } public void setState(String state) { this.state = state; } /** * 生成备忘录 * @return */ public Memento createMemento(){ return new Memento(state); } public void restoreMemento(Memento memento){ this.setState(memento.getState()); } }
3、 备忘录保存的类
package memento.patten; public class Caretaker { private Memento memento; public Memento getMemento() { return memento; } public void setMemento(Memento memento) { this.memento = memento; } }
5、客户端调用
package memento.patten; public class Client { public static void main(String[] args) { Originator originator=new Originator(); originator.setState("状态1"); System.out.println("初始状态为:"+originator.getState()); Caretaker caretaker=new Caretaker(); caretaker.setMemento(originator.createMemento()); originator.setState("状态2"); System.out.println("当前状态为:"+originator.getState()); //恢复备份 originator.restoreMemento(caretaker.getMemento()); System.out.println("恢复后状态为:"+originator.getState()); } }
三、疑问
以上是备忘录模式的UML图,一直以来的模式均为提供UML图,但是备忘录是个特例,有几个问题需要这里:
1、发起人需要确定保存哪些信息,并提供保存和还原方法,整个设计模式缺少了对被保存对象的定义所以看起来并不完整
2、管理角色目前仅提供了备忘录的引用,实际中可能存在多个备忘录的保存,因此需要保存备忘录集合
所以我们在场景中需要进行完善。
四、场景
由于做的大部分项目对于功能节点的保存和还原均使用持久化技术,包括数据库和问题进行保存,因此使用备忘录的模式很少,不过我们仍然可以通过一些常见的场景进行模拟。
我们进场玩的单机游戏,有如下元素
游戏界面:人物显示,调取存档指令,还原指令
人物:游戏角色,有等级、血量、防御、经验的要素,人物有工具,防守,升级的动作
存档:存档中不需要人物动作,只需要保留基本信息即可
存档中心:可以保存多个存档
客户端:客户仅和游戏界面进行打交道
五、场景代码
package memento.example; /** * 游戏类, * 游戏的主界面,主要运行游戏,生成存档以及还原存储 * 此处省略运行游戏逻辑 * @author zjl * @time 2016-2-1 * */ public class Game { //游戏角色 public Role role; public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } public SaveCenter center=new SaveCenter(); public void createSave(int pos,Role role){ center.save(pos, new Save(role)); } public void restoreSave(int pos){ this.role.setLevel(center.getSave(pos).getLevel()); } }
2、游戏角色
package memento.example; /** * 游戏角色,有等级,生命,攻击力,防守力 * @author zjl * @time 2016-2-1 * */ public class Role { private int level; private int vit;//生命 private int atk;//攻击力 private int def;//防守 public Role(int level){ this.setLevel(level); } public void setLevel(int level){ this.level=level; this.vit=level*400; this.atk=level*20; this.def=level*5; } public int getLevel(){ return this.level; } public int getVit() { return vit; } public void setVit(int vit) { this.vit = vit; } public int getAtk() { return atk; } public void setAtk(int atk) { this.atk = atk; } public int getDef() { return def; } public void setDef(int def) { this.def = def; } public void levelup(){ setLevel(this.level+1); } @Override public String toString() { return "Role [level=" + level + ", vit=" + vit + ", atk=" + atk + ", def=" + def + "]"; } }
3、游戏存档
package memento.example; /** * 游戏存档,保存任务等级,如果有其他信息也可以一并保存 * @author zjl * @time 2016-2-1 * */ public class Save { private int level; public Save(Role role){ this.level=role.getLevel(); } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } }
4、存档中心
package memento.example; import java.util.HashMap; import java.util.Map; /** * 存档中心 * 可以有多个存档,根据位置进行保存 * @author zjl * @time 2016-2-1 * */ public class SaveCenter { public Map<Integer, Save> map=new HashMap<Integer, Save>(); public void save(int pos,Save save){ map.put(pos, save); } public Save getSave(int pos){ return map.get(pos); } }
5、玩家界面
package memento.example; public class Client { public static void main(String[] args) { Game game=new Game(); Role lixiaoyao=new Role(1); game.setRole(lixiaoyao); System.out.println(game.getRole()); game.createSave(1, game.getRole()); game.getRole().levelup(); System.out.println(game.getRole()); game.getRole().levelup(); System.out.println(game.getRole()); game.restoreSave(1); System.out.println(game.getRole()); } }
6、执行结果
Role [level=1, vit=400, atk=20, def=5] Role [level=2, vit=800, atk=40, def=10] Role [level=3, vit=1200, atk=60, def=15] Role [level=1, vit=400, atk=20, def=5]