目录
备忘录模式(Memento)
UML图
示例代码
适用场景
优缺点
备忘录模式和原型模式
例子——游戏进度存档
例子——象棋中的悔棋
备忘录模式(Memento)
本质:保存和恢复内部状态
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以后就可以利用保存的状态实施恢复。
为什么要增加一个备忘录类?
如果在Originator类中再增加一个方法来保存这个状态,则是对单一职责原则的一种破坏。
在游戏存档例子中,Gamerole类的职责就是打boss,而保留和恢复原始状态则应该由另外一个类来承担,那我们把这个类取名就叫做备忘录
UML图

Originator(发起人):需要被存储和恢复状态的角色
- 创建一个备忘录,存储自己的当前内部状态
- 使用备忘录来恢复自己的内部状态
Memento(备忘录):(类的设计参考发起人)
存储发起人的内部状态,根据实际需要确定备忘录类中的属性。
Caretaker(管理者):
存储一个或多个备忘录对象,但只负责存储,所以不能修改对象,也无须知道对象的实现细节。
存储多个备忘录对象时,可以使用list+泛型
示例代码
//发起人类
public class Originator {private String state;public String getState() {return state;}public void setState(String state) {this.state = state;}public Memento CreateMemento() {return new Memento(state);}//恢复状态public void SetMemento(Memento memento) {state=memento.getState();}public void show() {System.out.println("state:"+state);}
}
//备忘录类
public class Memento {private String state;public Memento(String state) {super();this.state = state;}public String getState() {return state;}}
//管理者类
public class CareTaker {private Memento memento;public Memento getMemento() {return memento;}public void setMemento(Memento memento) {this.memento = memento;}}
public class Main {public static void main(String[] args) {Originator o=new Originator();o.setState("ON");//初始状态o.show();CareTaker c=new CareTaker();c.setMemento(o.CreateMemento());//保存状态o.setState("OFF");//改变状态o.show();o.SetMemento(c.getMemento());//恢复初始状态o.show();}}
适用场景
保存一个对象在某一个时刻的全部或部分状态,在以后需要时,把该对象恢复到先前的状态
优缺点
优点:
- 把发起人内部信息对外屏蔽,恰当地保持封装的边界:有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取
- 简化了发起人类:发起人不需要管理和保存其内部状态的一个个版本,客户端可以自行管理需要状态的版本。
- 当发起人对象的状态改变无效时,可以使用备忘录将状态复原。
缺点:
- 如果发起人对象的状态需要完整地存储到备忘录对象中,那么在备忘录对象可能会消耗很多资源。
- 管理者存储备忘录对象时,可能不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很大。
备忘录模式和原型模式
可以组合使用
在发起人对象创建备忘录对象时,如果发起人对象中全部或者大部分的状态都需要保存,一个简洁的方式就是直接克隆一个发起人对象。这时备忘录对象里存的是一个发起人对象的实例。
例子——游戏进度存档
public class GameRole {private int vit;//生命力private int atk;//攻击力private int def;//防御力//设置初始状态public void setInitState() {this.vit=100;this.atk=100;this.def=100;}//设置战后状态public void fight() {this.vit=0;this.atk=0;this.def=0;}//保存状态public RoleStateMemento saveState() {return new RoleStateMemento(vit,atk,def);}//恢复状态public void RecoverState(RoleStateMemento memento) {this.vit=memento.getVit();this.atk=memento.getAtk();this.def=memento.getDef();}//显示状态public void display() {System.out.println("vit=" + vit + ", atk=" + atk + ", def=" + def );}}
//角色状态存储箱
public class RoleStateMemento {private int vit;//生命力private int atk;//攻击力private int def;//防御力public RoleStateMemento(int vit, int atk, int def) {super();this.vit = vit;this.atk = atk;this.def = def;}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 class RoleStateCareTaker {private RoleStateMemento memento;public RoleStateMemento getMemento() {return memento;}public void setMemento(RoleStateMemento memento) {this.memento = memento;}}
public class Main {public static void main(String[] args) {//大战前GameRole lxy=new GameRole();lxy.setInitState();lxy.display();//保存进度RoleStateCareTaker state1=new RoleStateCareTaker();state1.setMemento(lxy.saveState());//大战后lxy.fight();lxy.display();//恢复原状态lxy.RecoverState(state1.getMemento());lxy.display();}}
例子——象棋中的悔棋

package com.chess;//发起人
public class ChessRole {private int x;private int y;private String name;private String color;public ChessRole(int x, int y, String name, String color) {super();this.x = x;this.y = y;this.name = name;this.color = color;}public ChessMemento createMemento() {return new ChessMemento(x,y,name,color);}public void getMemento(ChessMemento memento) {if(memento==null)return;this.x=memento.getX();this.y=memento.getY();this.name=memento.getName();this.color=memento.getColor();}public void setState(int x, int y, String name, String color) {this.x=x;this.y=y;this.name = name;this.color = color;}public void show() {System.out.println("坐标:x=" + x + ", y=" + y + ", name=" + name + ", color=" + color);}}
package com.chess;public class ChessMemento {private int x;private int y;private String name;private String color;public ChessMemento(int x, int y, String name, String color) {super();this.x = x;this.y = y;this.name = name;this.color = color;}public int getX() {return x;}public int getY() {return y;}public String getName() {return name;}public String getColor() {return color;}}
package com.chess;import java.util.ArrayList;public class ChessCareTaker {private ArrayList<ChessMemento> list=new ArrayList<ChessMemento>();public ChessCareTaker() {list=new ArrayList<ChessMemento>();}public void addMemento(ChessMemento memento) {list.add(memento);}public ChessMemento huiqi() {if(list.isEmpty()) {System.out.println("无法悔棋");return null;}else {int index=list.size();ChessMemento memento=(ChessMemento)list.get(index-1);list.remove(index-1);return memento;}}}
package com.chess;public class Main {public static void main(String[] args) {ChessRole c1=new ChessRole(0,0,"马1","红方");ChessCareTaker ct1=new ChessCareTaker();ct1.addMemento(c1.createMemento());c1.show();c1.setState(1, 2, "马1", "红方");ct1.addMemento(c1.createMemento());c1.show();c1.setState(3, 5, "象2", "红方");c1.show();System.out.println("悔棋一步:");c1.getMemento(ct1.huiqi());c1.show();System.out.println("悔棋二步:");c1.getMemento(ct1.huiqi());c1.show();}}
















