一、概念:
备忘录:在不破坏封装性的前提下,捕获一个对象的内部状态,并在对象之外保存这个状态,这样以后可以将该对象恢复到原来保存的状态。
二、类图以及基本代码
//发起者
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){
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 Show {
public static void main(String[] args) {
Originator originator=new Originator();
originator.setState("ON");
originator.show();
Caretaker caretaker=new Caretaker();//管理者类
caretaker.setMemento(originator.createMemento());//存储备忘录类
originator.setState("Off");
originator.show();
originator.setMemento(caretaker.getMemento());//恢复备忘录类
originator.show();
}
}
三、案例
游戏存进度,角色有生命力,攻击力,防御力三个属性,在角色战斗后,可恢复到满状态
(1).未使用备忘录模式
//游戏角色类
public class GameRole {
private int vit;//生命力
public int getVit() {
return vit;
}
public void setVit(int vit) {
this.vit = vit;
}
private int atk;//攻击力
public int getAtk() {
return atk;
}
public void setAtk(int atk) {
this.atk = atk;
}
private int def;//防御力
public int getDef() {
return def;
}
public void setDef(int def) {
this.def = def;
}
/*
* 显示状态
*/
public void StateDisplay(){
System.out.println("角色的当前状态: ");
System.out.println("体力 "+vit);
System.out.println("攻击力 "+atk);
System.out.println("防御力 "+def);
}
/*
* 初始状态
*/
public void GetInitState(){
this.atk=100;
this.vit=100;
this.def=100;
}
/*
* 战斗
*/
public void Fight(){
this.vit=0;
this.atk=0;
this.def=0;
}
}
public class Show {
public static void main(String[] args) {
GameRole gameRole=new GameRole();
gameRole.GetInitState();
gameRole.StateDisplay();
GameRole backup=new GameRole();//同过一个新的实例来保存进度
backup.setVit(gameRole.getVit());
backup.setDef(gameRole.getDef());
backup.setAtk(gameRole.getAtk());
gameRole.Fight();
gameRole.StateDisplay();
gameRole.setAtk(backup.getAtk());
gameRole.setDef(backup.getDef());
gameRole.setVit(backup.getVit());
gameRole.StateDisplay();
}
(2).使用备忘录模式
/*
* 角色类
*/
public class GameRole {
private int vit;// 生命力
private int atk;// 攻击力
private int 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 RoleStateMemento SaveState(){
return new RoleStateMemento(vit, atk, def);
}
/*
* 读档
*/
public void RecoveryState(RoleStateMemento memento){
this.def=memento.getDef();
this.atk=memento.getAtk();
this.vit=memento.getVit();
}
/*
* 显示状态
*/
public void StateDisplay(){
System.out.println("角色的当前状态: ");
System.out.println("体力 "+vit);
System.out.println("攻击力 "+atk);
System.out.println("防御力 "+def);
}
/*
* 初始状态
*/
public void GetInitState(){
this.atk=100;
this.vit=100;
this.def=100;
}
/*
* 战斗
*/
public void Fight(){
this.vit=0;
this.atk=0;
this.def=0;
}
}
/*
* 角色状态备忘录类
*/
public class RoleStateMemento {
private int vit;// 生命力
private int atk;// 攻击力
private int def;// 防御力
public RoleStateMemento(int vit,int atk,int def){
this.def=def;
this.vit=vit;
this.atk=atk;
}
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 Show {
public static void main(String[] args) {
GameRole gameRole=new GameRole();//战斗前
gameRole.GetInitState();
gameRole.StateDisplay();
RoleStateCaretaker roleStateCaretaker=new RoleStateCaretaker();
roleStateCaretaker.setMemento(gameRole.SaveState());//存档
gameRole.Fight();//战斗后
gameRole.StateDisplay();
gameRole.RecoveryState(roleStateCaretaker.getMemento());//读档
gameRole.StateDisplay();
}
}
四、总结
(1).在未使用备忘录设计模式前,游戏存进度是通过一个新的游戏角色实例来实现的,这样游戏角色的属性都暴露给了客户端,不易于后面的修改,如游戏角色新增一个新的属性,就要修改很多地方,这里便出现了代码的坏味道。备忘录设计模式所做的就是将游戏角色的具体存取细节封装到备忘录类中,以完成职责的分离,进而提高代码的可维护性。
(2).在需要保存全部信息时,可以尝试用clone的方式来实现状态保存,但这样会向上层应用开放了发起者类(Originator)的全部public,这样对于保存备份有时是不合适的。
Life may always have regret, but the future is still good.