设计模式之备忘录模式

1、备忘录模式(Memento):

在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

Originator(发起人):

负责创建一个备忘录Memento,用以记录当前时刻它的内部状态,并可以使用备忘录恢复内部状态。Originator可根据需要决定Memento存储Originator的那些内部状态。

Memento(备忘录):

负责存储Originator对象内部状态,并可防止Originator以外的其他对象访问备忘录Memento。备忘录有两个接口,caretaker只能看到备忘录的窄接口,它只能将备忘录传递给其他对象。Originator能够看到一个宽接口,允许它访问返回到先前状态所需的所有数据。

Caretaker(管理者):

负责保存好备忘录Memento,不能对备忘录的内容进行操作或检查。保存的细节给封装在了Memento中了,那一天要更改保存细节也不用影响客户端了。


2、Memento模式比较适用于功能比较复杂的,但是需要维护或记录属性历史的类,或者需要保存的属性只是众多属性中的一小部分时。Originator可以根据保存的Memento信息还原到前一状态。

如果在某个系统中使用命令模式时,需要实现命令的撤销功能,那么命令模式可以使用备忘录模式来存储可撤销操作的状态。


3、使用备忘录模式可以把复杂对象内部信息对其他的对象屏蔽起来。当角色的状态改变的时候,有可能这个状态无效,这时候就可以使用暂时存储起来的备忘录将状态复原。

UML图如下:


4、C++代码实现

[cpp] view plaincopy
 
  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. /* 备忘录(Memento)类 */  
  6. class Memento   
  7. {  
  8. private:  
  9.     string state;  
  10. public:  
  11.     Memento();  
  12.     /* 构造函数,将相关的数据导入 */  
  13.     Memento(string);  
  14.     /* 需要保存的数据属性,可以是多个 */  
  15.     string GetState();  
  16. };  
  17.   
  18. Memento::Memento() {  
  19.       
  20. }  
  21.   
  22. Memento::Memento(string state) {  
  23.     Memento::state = state;  
  24. }  
  25.   
  26. string Memento::GetState() {  
  27.     return Memento::state;  
  28. }  
  29.   
  30. /* 发起人:Originator类 */  
  31. class Originator  
  32. {     
  33. public:  
  34.     /* 需要保存的状态,实际情况可能有多个  */  
  35.     string state;     
  36.     /* 创建备忘录,将当前需要保存的信息 
  37.         导入并实例化出一个Memento对象。 */  
  38.     Memento CreateMemento();  
  39.     /* 恢复备忘录,将Memento导 
  40.         入,并将相关数据恢复。 */  
  41.     void SetMemento(Memento &);  
  42.     /* 显示状态信息 */  
  43.     void Show();  
  44. };  
  45.   
  46. Memento Originator::CreateMemento() {  
  47.     return Memento(state);  
  48. }  
  49.   
  50. void Originator::SetMemento(Memento & memento) {  
  51.     state = memento.GetState();  
  52. }  
  53.   
  54. void Originator::Show() {  
  55.     cout << "State = " << state << endl;  
  56. }  
  57.   
  58. /* 管理(Caretaker)类 */  
  59. class Caretaker  
  60. {  
  61. private:  
  62.     Memento memento;  
  63. public:  
  64.     /* 设置备忘录  */  
  65.     void SetMemento(Memento memento);  
  66.     /* 得到备忘录 */  
  67.     Memento GetMemento();  
  68. };  
  69.   
  70. void Caretaker::SetMemento(Memento memento)   
  71. {  
  72.     Caretaker::memento = memento;  
  73. }  
  74.   
  75. Memento Caretaker::GetMemento()  
  76. {  
  77.     return memento;  
  78. }  
  79.   
  80. int main()  
  81. {  
  82.     Originator originator;  
  83.     originator.state = "on";  
  84.     originator.Show();  
  85.   
  86.     Caretaker caretaker;  
  87.     /*  备份Originator的状态  */  
  88.     caretaker.SetMemento(originator.CreateMemento());  
  89.     originator.state = "off";  
  90.     originator.Show();  
  91.     /* 恢复Originator备份的状态 */  
  92.     originator.SetMemento(caretaker.GetMemento());  
  93.     originator.Show();  
  94.     return 0;  
  95. }  

再举一个实际一点的例子:

  备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态[DP]。举个简单的例子,我们玩游戏时都会保存进度,所保存的进度以文件的形式存在。这样下次就可以继续玩,而不用从头开始。这里的进度其实就是游戏的内部状态,而这里的文件相当于是在游戏之外保存状态。这样,下次就可以从文件中读入保存的进度,从而恢复到原来的状态。这就是备忘录模式。

        给出备忘录模式的UML图,以保存游戏的进度为例。


      Memento类定义了内部的状态,而Caretake类是一个保存进度的管理者,GameRole类是游戏角色类。可以看到GameRole的对象依赖于Memento对象,而与Caretake对象无关。下面给出一个简单的是实现。

  1. /需保存的信息  
  2. class Memento    
  3. {  
  4. public:  
  5.     int m_vitality; //生命值  
  6.     int m_attack;   //进攻值  
  7.     int m_defense;  //防守值  
  8. public:  
  9.     Memento(int vitality, int attack, int defense):   
  10.       m_vitality(vitality),m_attack(attack),m_defense(defense){}  
  11.     Memento& operator=(const Memento &memento)   
  12.     {  
  13.         m_vitality = memento.m_vitality;  
  14.         m_attack = memento.m_attack;  
  15.         m_defense = memento.m_defense;  
  16.         return *this;  
  17.     }  
  18. };  
  19. //游戏角色  
  20. class GameRole    
  21. {  
  22. private:  
  23.     int m_vitality;  
  24.     int m_attack;  
  25.     int m_defense;  
  26. public:  
  27.     GameRole(): m_vitality(100),m_attack(100),m_defense(100) {}  
  28.     Memento Save()  //保存进度,只与Memento对象交互,并不牵涉到Caretake  
  29.     {   
  30.         Memento memento(m_vitality, m_attack, m_defense);  
  31.         return memento;  
  32.     }  
  33.     void Load(Memento memento)  //载入进度,只与Memento对象交互,并不牵涉到Caretake  
  34.     {  
  35.         m_vitality = memento.m_vitality;  
  36.         m_attack = memento.m_attack;   
  37.         m_defense = memento.m_defense;  
  38.     }  
  39.     void Show() { cout<<"vitality : "<< m_vitality<<", attack : "<< m_attack<<", defense : "<< m_defense<<endl; }  
  40.     void Attack() { m_vitality -= 10; m_attack -= 10;  m_defense -= 10; }  
  41. };  
  42. //保存的进度库  
  43. class Caretake    
  44. {  
  45. public:  
  46.     Caretake() {}  
  47.     void Save(Memento menento) { m_vecMemento.push_back(menento); }  
  48.     Memento Load(int state) { return m_vecMemento[state]; }  
  49. private:  
  50.     vector<Memento> m_vecMemento;  
  51. };  

客户使用方式:

  1. //测试案例  
  2. int main()  
  3. {     
  4.     Caretake caretake;  
  5.     GameRole role;   
  6.     role.Show();   //初始值  
  7.     caretake.Save(role.Save()); //保存状态  
  8.     role.Attack();     
  9.     role.Show();  //进攻后  
  10.     role.Load(caretake.Load(0)); //载入状态   
  11.     role.Show();  //恢复到状态0  
  12.     return 0;  
  13. }  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值