1. 意图
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
2. 动机
有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制, 而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到它们先前的状态。但是对象通常封装了其部分或所有的状态信息, 使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
2. 动机
有时有必要记录一个对象的内部状态。为了允许用户取消不确定的操作或从错误中恢复过来,需要实现检查点和取消机制, 而要实现这些机制,你必须事先将状态信息保存在某处,这样才能将对象恢复到它们先前的状态。但是对象通常封装了其部分或所有的状态信息, 使得其状态不能被其他对象访问,也就不可能在该对象之外保存其状态。而暴露其内部状态又将违反封装的原则,可能有损应用的可靠性和可扩展性。
3.结构
• M e m e n t o(备忘录,如S o l v e r S t a t e )
— 备忘录存储原发器对象的内部状态。原发器根据需要决定备忘录存储原发器的哪些内部状态。
— 防止原发器以外的其他对象访问备忘录。备忘录实际上有两个接口,管理者( c a r e t a k e r )只能看到备忘录的窄接口—它只能将备忘录传递给其他对象。相反, 原发器能够看到一个宽接口, 允许它访问返回到先前状态所需的所有数据。理想的情况是只允许生成本备忘录的那个原发器访问本备忘录的内部状态。
• O r i g i n a t o r(原发器,如C o n s t r a i n t S o l v e r )
— 原发器创建一个备忘录,用以记录当前时刻它的内部状态。
— 使用备忘录恢复内部状态.。
• C a r e t a k e r(负责人,如undo mechanism)
— 负责保存好备忘录。
— 不能对备忘录的内容进行操作或检查。
UML类图:
4.举例
现在假设游戏角色中有两个属性,角色名称和角色生命值,现在要进行的保存游戏角色的生命值,但是游戏角色名称不用保存。
C++代码:
#ifndef MEMENTO_H
#define MEMENTO_H
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class CMemento{
private:
int iVitality;
public:
CMemento(int temp):iVitality(temp){}
int GetVitality(){
return iVitality;
}
};
class CGameRole{
private:
string name;
int iVitality;
public:
CGameRole(string data,int value):name(data),iVitality(value){}
CMemento SaveState(){
CMemento temp(iVitality);
return temp;
}
void RecoverState(CMemento temp){
iVitality=temp.GetVitality();
}
void Show(){
cout<<name<<": "<<iVitality<<endl;
}
void Fight(){
iVitality=0;
}
};
class CCareTaker{
private:
CMemento mem;
public:
CCareTaker():mem(NULL){}
void SetMemento(CMemento temp){
mem=temp;
}
CMemento GetMemento(){
return mem;
}
};
#endif
#include "memento.h"
int main(){
CGameRole James("James",100);
cout<<"Before the fighting"<<endl;
James.Show();
CCareTaker Mem;
Mem.SetMemento(James.SaveState());
James.Fight();
cout<<"After the fighting"<<endl;
James.Show();
James.RecoverState(Mem.GetMemento());
cout<<"Recovering the vitality"<<endl;
James.Show();
return 0;
}