备忘录模式(Token)
一、定义
在不破坏封闭的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
二、适用场景
适合于功能比较复杂,但需要维护或记录属性历史的功能。
参与者:
Originator(发起人):负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memento存储自己的哪些内部状态。
Memento(备忘录):负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它访问返回到先前状态所需要的所有数据。
Caretaker(管理者):负责备忘录Memento,不能对Memento的内容进行访问或者操作。
适用性:
1)必须保存一个对象在某一时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
2)如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
效果:
1)保持封装边界
2)简化原发器
3)使用备忘录可能代价很高
4)定义窄接口和宽接口
5)维护备忘录的潜在代价
三、UML
四、代码
- /**
- * 游戏自身(备忘录模式中的发起人,备份的是游戏的状态)
- */
- public class Game {
-
- /**
- * 英雄状态属性
- */
- private HeroState hState;
-
- /**
- * 场景状态属性
- */
- private SceneState sState;
-
- public HeroState gethState() {
- return hState;
- }
-
- public void sethState(HeroState hState) {
- this.hState = hState;
- }
-
- public SceneState getsState() {
- return sState;
- }
-
- public void setsState(SceneState sState) {
- this.sState = sState;
- }
-
- /**
- * 备份游戏
- */
- public GameMemento createMemento(){
- return new GameMemento(hState,sState);
- }
-
- /**
- * 玩游戏
- * @throws InterruptedException
- */
- public void play(){
- hState.setHP(0);
- hState.setMP(0);
- sState.setCoin(0);
- sState.setWood(0);
- }
-
- /**
- * 游戏还原
- */
- public void restore(GameMemento memento){
- this.hState = memento.gethState();
- this.sState = memento.getsState();
- }
- }
点击(此处)折叠或打开
- /**
- * 游戏英雄人物状态实体
- */
- public class HeroState implements Cloneable{
-
- /**
- * 英雄生命值
- */
- private int HP;
-
- /**
- * 英雄魔法值
- */
- private int MP;
-
- /**
- * 状态保存时间
- */
- private Date stateDate;
-
- public int getHP() {
- return HP;
- }
-
- public void setHP(int hP) {
- HP = hP;
- }
-
- public int getMP() {
- return MP;
- }
-
- public void setMP(int mP) {
- MP = mP;
- }
-
- public Date getStateDate() {
- return stateDate;
- }
-
- public void setStateDate(Date stateDate) {
- this.stateDate = stateDate;
- }
-
- public HeroState clone(){
- try {
- return (HeroState) super.clone();
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- }
点击(此处)折叠或打开
- /**
- * 游戏场景状态实体
- */
- public class SceneState implements Cloneable{
-
- /**
- * 金币数量
- */
- private int coin;
-
- /**
- * 木材数量
- */
- private int wood;
-
- /**
- * 地图名称
- */
- private String mapName;
-
- public int getCoin() {
- return coin;
- }
-
- public void setCoin(int coin) {
- this.coin = coin;
- }
-
- public int getWood() {
- return wood;
- }
-
- public void setWood(int wood) {
- this.wood = wood;
- }
-
- public String getMapName() {
- return mapName;
- }
-
- public void setMapName(String mapName) {
- this.mapName = mapName;
- }
-
- public SceneState clone(){
- try {
- return (SceneState) super.clone();
- } catch (CloneNotSupportedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return null;
- }
- }
点击(此处)折叠或打开
- /**
- * 游戏备忘录角色
- */
- public class GameMemento{
-
- /**
- * 英雄状态
- */
- private HeroState hState;
-
- /**
- * 场景状态
- */
- private SceneState sState;
-
- /**
- * 构造方法
- * @param hState
- * @param sState
- */
- public GameMemento(HeroState hState,SceneState sState){
- this.hState = hState.clone();
- this.sState = sState.clone();
- }
-
- /**
- * 获取备份状态
- * @return
- */
- public HeroState gethState() {
- return hState;
- }
-
- /**
- * 获取备份状态
- * @return
- */
- public SceneState getsState() {
- return sState;
- }
- }
点击(此处)折叠或打开
- /**
- * 备忘录管理器
- */
- public class Caretaker {
-
- /**
- * 备忘录实体
- */
- private GameMemento memento;
-
- public GameMemento getMemento() {
- return memento;
- }
-
- public void setMemento(GameMemento memento) {
- this.memento = memento;
- }
- }
点击(此处)折叠或打开
- /**
- * 测试Main方法
- */
- public class TestMain {
-
- public static void main(String [] args){
- Game game = new Game();
- HeroState hState = new HeroState();
- hState.setHP(100);
- hState.setMP(100);
- SceneState sState = new SceneState();
- sState.setCoin(1000);
- sState.setWood(1000);
- game.sethState(hState);
- game.setsState(sState);
- System.out.println("游戏状态备份开始");
- GameMemento memento = game.createMemento();
- Caretaker ct = new Caretaker();
- ct.setMemento(memento);
- System.out.println("游戏状态备份完成");
- System.out.println("开始游戏,当前英雄生命值:" + game.gethState().getHP());
- game.play();
- System.out.println("游戏结束,当前英雄生命值:" + game.gethState().getHP());
- System.out.println("游戏状态还原开始");
- game.restore(ct.getMemento());
- System.out.println("游戏状态还原结束");
- System.out.println("当前英雄生命值:" + game.gethState().getHP());
- }
- }
五、总结
备忘录模式
优点:
1)在同一个集合上可有多个状态一起工作
2)不需要为支持迭代而破坏一个集合的封装性。
缺点:
将对象状态备份会占用比较多的系统资源。