作为一个编程菜鸟,过去在学习设计模式的时候,老师给推荐了一本《大话设计模式》。阅读以后受益匪浅,可惜当初没有坚持看完。
最近有时间了,又重新捡起来学习了一遍,整理了一下笔记,由于本人能力有限,欢迎大家批评指正。
1.备忘录模式 Memento Pattern
- 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
- 又叫做快照模式或Token模式,属于行为模式。把要保存的细节给封装在了Memento中,当要更改保存的细节时无须修改客户端,适用于功能比较复杂的,但需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一部分时,Originator可以根据保存的Memento信息还原到前一状态。
2.备忘录模式的优点和缺点
(1)优点
- 有时一些发起人对象的内部信息必须保存在发起人对象以外的地方,但是必须要由发起人对象自己读取,这时,使用备忘录模式可以把复杂的发起人内部信息对其他的对象屏蔽起来,从而可以恰当地保持封装的边界。
- 本模式简化了发起人类。发起人不再需要管理和保存其内部状态的一个个版本,客户端可以自行管理他们所需要的这些状态的版本。
- 当发起人角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
(2)缺点
- 如果发起人角色的状态需要完整地存储到备忘录对象中,那么在资源消耗上面备忘录对象会很昂贵。
- 当负责人角色将一个备忘录存储起来的时候,负责人可能并不知道这个状态会占用多大的存储空间,从而无法提醒用户一个操作是否很昂贵。
- 当发起人角色的状态改变的时候,有可能这个协议无效。如果状态的成功率不高的话,不如采取“假如”协议模式。
3.uml类图
4.组成
(1)Originator 发起人
负责创建一个备忘录Memento,用以记录当前时刻自身的内部状态,并可使用备忘录恢复内部状态。Originator可以根据需要决定Memeton存储自己的哪些内部状态。
(2)Memento 备忘录
负责存储Originator对象的内部状态,并可以防止Originator以外的其他对象访问备忘录。备忘录有两个接口:Caretaker只能看到备忘录的窄接口,他只能将备忘录传递给其他对象。Originator却可看到备忘录的宽接口,允许它返回到先前状态所需要的所有数据。
(3)Caretaker 管理者
负责备忘录Memnto,不能对Memento的内容进行访问或者操作。
5.实例
(1)需求
一个游戏,允许玩家在与boss决斗前对游戏进行备份。
(2)uml类图
(3)代码
a.游戏角色类
package com.longinus.mp;
public class GameRole {
private int vitality;
private int attack;
private int defense;
public int getVitality() {
return vitality;
}
public void setVitality(int vitality) {
this.vitality = vitality;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefense() {
return defense;
}
public void setDefense(int defense) {
this.defense = defense;
}
public void stateDisplay(){
System.out.println("角色当前状态:");
System.out.println("体力:" + getVitality());
System.out.println("攻击力:" + getAttack());
System.out.println("防御力:" + getDefense());
}
public void getInitState(){
setVitality(100);
setAttack(100);
setDefense(100);
}
public void fight(){
setVitality(0);
setAttack(0);
setDefense(0);
}
public StateMemento saveState(){
return new StateMemento(getVitality(), getAttack(), getDefense());
}
public void recoverState(StateMemento sm){
vitality = sm.getVitality();
attack = sm.getAttack();
defense = sm.getDefense();
}
}
b.状态备忘录类
package com.longinus.mp;
public class StateMemento {
private int vitality;
private int attack;
private int defense;
public int getVitality() {
return vitality;
}
public void setVitality(int vitality) {
this.vitality = vitality;
}
public int getAttack() {
return attack;
}
public void setAttack(int attack) {
this.attack = attack;
}
public int getDefense() {
return defense;
}
public void setDefense(int defense) {
this.defense = defense;
}
public StateMemento(int v,int a,int d) {
// TODO Auto-generated constructor stub
vitality = v;
attack = a;
defense = d;
}
}
c.状态管理者类
package com.longinus.mp;
public class StateManager {
private StateMemento sm;
public StateMemento getSm() {
return sm;
}
public void setSm(StateMemento sm) {
this.sm = sm;
}
}
d.测试类
package com.longinus.mp;
public class Test {
public static void main(String[] args) {
GameRole gr = new GameRole();
StateManager sm = new StateManager();
System.out.println("游戏角色登场");
gr.getInitState();
gr.stateDisplay();
System.out.println("存档");
sm.setSm(gr.saveState());
System.out.println("游戏角色挑战boss");
gr.fight();
gr.stateDisplay();
System.out.println("读取存档");
gr.recoverState(sm.getSm());
gr.stateDisplay();
}
}
e.输出结果
游戏角色登场
角色当前状态:
体力:100
攻击力:100
防御力:100
存档
游戏角色挑战boss
角色当前状态:
体力:0
攻击力:0
防御力:0
读取存档
角色当前状态:
体力:100
攻击力:100
防御力:100