1、备忘录模式(Memento):
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
Originator(发起人):
负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的那些内部状态。
Memento(备忘录):
负责存储Originator对象内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。
Caretaker(管理者):
负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。保存的细节给封装在了Memento中了,那一天要更改保存细节也不用影响客户端了。
2、Memento模式比较适用于功能比较复杂的,但是需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时。Originator可以根据保存的Memento信息还原到前一状态。
如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。
3、使用备忘录模式可以把复杂对象内部信息对其他的对象屏蔽起来。当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。
UML图如下:
4、C++代码实现
- #include <iostream>
- #include <string>
- using namespace std;
- /* 备忘录(Memento)类 */
- class Memento
- {
- private:
- string state;
- public:
- Memento();
- /* 构造函数,将相关的数据导入 */
- Memento(string);
- /* 需要保存的数据属性,可以是多个 */
- string GetState();
- };
- Memento::Memento() {
- }
- Memento::Memento(string state) {
- Memento::state = state;
- }
- string Memento::GetState() {
- return Memento::state;
- }
- /* 发起人:Originator类 */
- class Originator
- {
- public:
- /* 需要保存的状态,实际情况可能有多个 */
- string state;
- /* 创建备忘录,将当前需要保存的信息
- 导入并实例化出一个Memento对象。 */
- Memento CreateMemento();
- /* 恢复备忘录,将Memento导
- 入,并将相关数据恢复。 */
- void SetMemento(Memento &);
- /* 显示状态信息 */
- void Show();
- };
- Memento Originator::CreateMemento() {
- return Memento(state);
- }
- void Originator::SetMemento(Memento & memento) {
- state = memento.GetState();
- }
- void Originator::Show() {
- cout << "State = " << state << endl;
- }
- /* 管理(Caretaker)类 */
- class Caretaker
- {
- private:
- Memento memento;
- public:
- /* 设置备忘录 */
- void SetMemento(Memento memento);
- /* 得到备忘录 */
- Memento GetMemento();
- };
- void Caretaker::SetMemento(Memento memento)
- {
- Caretaker::memento = memento;
- }
- Memento Caretaker::GetMemento()
- {
- return memento;
- }
- int main()
- {
- Originator originator;
- originator.state = "on";
- originator.Show();
- Caretaker caretaker;
- /* 备份Originator的状态 */
- caretaker.SetMemento(originator.CreateMemento());
- originator.state = "off";
- originator.Show();
- /* 恢复Originator备份的状态 */
- originator.SetMemento(caretaker.GetMemento());
- originator.Show();
- return 0;
- }
再举一个实际一点的例子:
备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态[DP]。举个简单的例子,我们玩游戏时都会保存进度,所保存的进度以文件的形式存在。这样下次就可以继续玩,而不用从头开始。这里的进度其实就是游戏的内部状态,而这里的文件相当于是在游戏之外保存状态。这样,下次就可以从文件中读入保存的进度,从而恢复到原来的状态。这就是备忘录模式。
给出备忘录模式的UML图,以保存游戏的进度为例。
Memento类定义了内部的状态,而Caretake类是一个保存进度的管理者,GameRole类是游戏角色类。可以看到GameRole的对象依赖于Memento对象,而与Caretake对象无关。下面给出一个简单的是实现。
- /需保存的信息
- class Memento
- {
- public:
- int m_vitality; //生命值
- int m_attack; //进攻值
- int m_defense; //防守值
- public:
- Memento(int vitality, int attack, int defense):
- m_vitality(vitality),m_attack(attack),m_defense(defense){}
- Memento& operator=(const Memento &memento)
- {
- m_vitality = memento.m_vitality;
- m_attack = memento.m_attack;
- m_defense = memento.m_defense;
- return *this;
- }
- };
- //游戏角色
- class GameRole
- {
- private:
- int m_vitality;
- int m_attack;
- int m_defense;
- public:
- GameRole(): m_vitality(100),m_attack(100),m_defense(100) {}
- Memento Save() //保存进度,只与Memento对象交互,并不牵涉到Caretake
- {
- Memento memento(m_vitality, m_attack, m_defense);
- return memento;
- }
- void Load(Memento memento) //载入进度,只与Memento对象交互,并不牵涉到Caretake
- {
- m_vitality = memento.m_vitality;
- m_attack = memento.m_attack;
- m_defense = memento.m_defense;
- }
- void Show() { cout<<"vitality : "<< m_vitality<<", attack : "<< m_attack<<", defense : "<< m_defense<<endl; }
- void Attack() { m_vitality -= 10; m_attack -= 10; m_defense -= 10; }
- };
- //保存的进度库
- class Caretake
- {
- public:
- Caretake() {}
- void Save(Memento menento) { m_vecMemento.push_back(menento); }
- Memento Load(int state) { return m_vecMemento[state]; }
- private:
- vector<Memento> m_vecMemento;
- };
客户使用方式:
- //测试案例
- int main()
- {
- Caretake caretake;
- GameRole role;
- role.Show(); //初始值
- caretake.Save(role.Save()); //保存状态
- role.Attack();
- role.Show(); //进攻后
- role.Load(caretake.Load(0)); //载入状态
- role.Show(); //恢复到状态0
- return 0;
- }