亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

C++設計模式之備忘錄模式

2020-01-26 15:16:03
字體:
來源:轉載
供稿:網友

前言

又到年底了,也靜不下心來寫代碼了,大家都很浮躁;翻出經典的《仙劍奇俠傳》玩一會;又要打大BOSS,先存一下檔吧。這是我的習慣,在打大BOSS之前,都要先存一下檔,要是打贏了,就再存一個檔,覆蓋之前的;如果打輸了,就恢復之前的存檔,接著重來。我想大家都是這么玩的吧。哎呀,總是打不過。好了,不玩了,但是,游戲中的那個存檔行為卻讓我很著迷,它是如何實現的呢?帶著好奇的心,去百度了一下;哦,原來如此。好吧,開始今天的總結吧――備忘錄模式。

備忘錄模式

在GOF的《設計模式:可復用面向對象軟件的基礎》一書中對備忘錄模式是這樣說的:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態。

有時有必要記錄一個對象的內部狀態。為了允許用戶取消不確定的操作或從錯誤中恢復過來,需要實現檢查點和取消機制,而要實現這些機制,你必須事先將狀態信息保存在某處,這樣才能將對象恢復到它們先前的狀態。如何實現這個將狀態信息保存在某處呢?使用原型模式?由于對象通常封裝了其部分或所有的狀態信息,使得其狀態不能被其他對象訪問,也就不可能在該對象之外保存其狀態了。由于原型模式總是返回對象的全部狀態信息,同時原型模式使其狀態能被其它對象訪問,這樣就違反了封裝的原則,還可能有損應用的可靠性和可擴展性。

再拿上面的《仙劍奇俠傳》進行分析,當我們在打大BOSS之前存檔,此時就需要將對應的游戲場景,任務信息,人物信息等等狀態存儲起來;當贏得大BOSS之后,覆蓋之前的存檔時,就將之前的存檔丟棄,新建立一個存檔,保存當前的狀態信息;如果打輸了,恢復存檔,就將之前的存檔信息讀取出來,還原到打大BOSS之前的游戲場景,重新開始打大BOSS。這里面就是使用的備忘錄模式。

一個備忘錄是一個對象,它存儲另一個對象在某個瞬間的內部狀態,而后者稱為備忘錄的原發器。當需要設置原發器的檢查點時,取消操作機制會向原發器請求一個備忘錄。原發器用描述當前狀態的信息初始化該備忘錄。只有原發器可以向備忘錄中存取信息,備忘錄對其他的對象是“不可見”的。

UML類圖

Memento:備忘錄存儲原發器對象的內部狀態。原發器根據需要決定備忘錄存儲原發器的哪些內部狀態;防止原發器以外的其他對象訪問備忘錄。備忘錄實際上有兩個接口,管理者只能看到備忘錄的窄接口――――它只能將備忘錄傳遞給其他對象。相反,原發器能夠看到一個寬接口,允許它訪問返回到先前狀態所需的所有數據。理想的情況是只允許生成備忘錄的那個原發器訪問本備忘錄的內部狀態;
Originator:原發器創建一個備忘錄,用以記錄當前時刻它的內部狀態;我們使用備忘錄恢復內部狀態;
Caretaker:負責保存好備忘錄;但是,不能對備忘錄的內容進行操作或檢查。

備忘錄模式是按照以下方式進行協作的:
管理器向原發器請求一個備忘錄,保留一段時間后,將其送回給原發器;而有的時候管理者不會將備忘錄返回給原發器,因為原發器可能根本不需要退到先前的狀態。備忘錄是被動的,只有創建備忘錄的原發器會對它的狀態進行賦值和檢索,如下面的時序圖:

使用場合

在以下情況下使用備忘錄模式:

1.必須保存一個對象在某一個時刻的部分或完整狀態,這樣以后需要時它才能恢復到先前的狀態;
2.如果一個用接口來讓其它對象直接得到這些狀態,將會暴露對象的實現細節并破壞對象的封裝性。

代碼實現:

復制代碼 代碼如下:

#include <iostream>
using namespace std;
 
struct State
{
     wchar_t wcsState[260];
};
 
class Memento
{
public:
     Memento(State *pState) : m_pState(pState){}
 
     State *GetState() { return m_pState; }
 
private:
     friend class Originator;
 
     State *m_pState;
};
 
class Originator
{
public:
     Originator() : m_pState(NULL) {}
     ~Originator()
     {
          // Delete the storage of the state
          if (m_pState)
          {
               delete m_pState;
               m_pState = NULL;
          }
     }
 
     void SetMemento(Memento *pMemento);
     Memento *CreateMemento();
 
     void SetValue(wchar_t *value)
     {
          memset(wcsValue, 0, 260 * sizeof(wchar_t));
          wcscpy_s(wcsValue, 260, value);
     }
 
     void PrintState() { wcout<<wcsValue<<endl; }
 
private:
     State *m_pState; // To store the object's state
 
     wchar_t wcsValue[260]; // This is the object's real data
};
 
Memento *Originator::CreateMemento()
{
     m_pState = new State;
     if (m_pState == NULL)
     {
          return NULL;
     }
 
     Memento *pMemento = new Memento(m_pState);
 
     wcscpy_s(m_pState->wcsState, 260, wcsValue); // Backup the value
     return pMemento;
}
 
void Originator::SetMemento(Memento *pMemento)
{
     m_pState = pMemento->GetState();
 
     // Recovery the data
     memset(wcsValue, 0, 260 * sizeof(wchar_t));
     wcscpy_s(wcsValue, 260, m_pState->wcsState);
}
 
// Manager the Memento
class Caretaker
{
public:
     Memento *GetMemento() { return m_pMemento; }
     void SetMemnto(Memento *pMemento)
     {
          // Free the previous Memento
          if (m_pMemento)
          {
               delete m_pMemento;
               m_pMemento = NULL;
          }
 
          // Set the new Memento
          m_pMemento = pMemento;
     }
 
private:
     Memento *m_pMemento;
};
 
int main()
{
     Originator *pOriginator = new Originator();
     pOriginator->SetValue(L"On");
     pOriginator->PrintState();
 
     // Now I backup the state
     Caretaker *pCaretaker = new Caretaker();
     pCaretaker->SetMemnto(pOriginator->CreateMemento());
 
     // Set the new state
     pOriginator->SetValue(L"Off");
     pOriginator->PrintState();
 
     // Recovery to the old state
     pOriginator->SetMemento(pCaretaker->GetMemento());
     pOriginator->PrintState();
 
     if (pCaretaker)
     {
          delete pCaretaker;
     }
 
     if (pOriginator)
     {
          delete pOriginator;
     }
 
     return 0;
}

我再根據上面的《仙劍奇俠傳》來完成備忘錄模式,代碼如下:

復制代碼 代碼如下:

#include <iostream>
using namespace std;
 
class RoleStateMemento
{
public:
     RoleStateMemento(unsigned iBlood, unsigned iAttack, unsigned iDefense) : m_iBlood(iBlood), m_iAttack(iAttack), m_iDefense(iDefense){}
 
private:
     friend class GameRole;
 
     unsigned GetBloodValue() { return m_iBlood; }
     unsigned GetAttackValue() { return m_iAttack; }
     unsigned GetDefenseValue() { return m_iDefense; }
 
     unsigned m_iBlood;   // 生命力
     unsigned m_iAttack;  // 攻擊力
     unsigned m_iDefense; // 防御力
};
 
class GameRole
{
public:
     GameRole() : m_iBlood(100), m_iAttack(100), m_iDefense(100){}
 
     // 存檔
     RoleStateMemento *SaveState() { return new RoleStateMemento(m_iBlood, m_iAttack, m_iDefense); }
 
     // 恢復存檔
     void RecoveryState(RoleStateMemento *pRoleState)
     {
          m_iBlood = pRoleState->GetBloodValue();
          m_iAttack = pRoleState->GetAttackValue();
          m_iDefense = pRoleState->GetDefenseValue();
          cout<<"Recovery..."<<endl;
     }
 
     void ShowState()
     {
          cout<<"Blood:"<<m_iBlood<<endl;
          cout<<"Attack:"<<m_iAttack<<endl;
          cout<<"Defense:"<<m_iDefense<<endl;
     }
 
     void Fight()
     {
          m_iBlood -= 100;
          m_iAttack -= 10;
          m_iDefense -= 20;
 
          if (m_iBlood == 0)
          {
               cout<<"Game Over"<<endl;
          }
     }
 
private:
     unsigned m_iBlood;   // 生命力
     unsigned m_iAttack;  // 攻擊力
     unsigned m_iDefense; // 防御力
};
 
class RoleStateCaretaker
{
public:
     void SetRoleStateMemento(RoleStateMemento *pRoleStateMemento) { m_pRoleStateMemento = pRoleStateMemento; }
     RoleStateMemento *GetRoleStateMemento() { return m_pRoleStateMemento; }
 
private:
     RoleStateMemento *m_pRoleStateMemento;
};
 
int main()
{
     GameRole *pLiXY = new GameRole(); // 創建李逍遙這個角色
     pLiXY->ShowState(); // 顯示初始的狀態
 
     // 存檔
     RoleStateCaretaker *pRoleStateCaretaker = new RoleStateCaretaker();
     pRoleStateCaretaker->SetRoleStateMemento(pLiXY->SaveState());
 
     // 開始打大BOSS
     pLiXY->Fight();
     pLiXY->ShowState();
 
     // 讀檔,從新開始
     pLiXY->RecoveryState(pRoleStateCaretaker->GetRoleStateMemento());
     pLiXY->ShowState();
 
     return 0;
}

總結

備忘錄模式在實際應用中也不少;我們在進行文檔編輯時,經常使用的撤銷操作。使用C++實現備忘錄模式的關鍵點在于Originator類是Memento的友元類,這樣就使得管理備忘錄的Caretaker對象,以及其它對象都不能讀取、設置備忘錄,只有Originator類才能進行備忘錄的讀取和設置。由于備忘錄主要是用于對對象的狀態進行備份,實現了撤銷操作,如果對象的狀態數據很大很多時,在進行備忘時,就會很占用資源,這個是我們在實際開發時需要考慮的東西。結合之前的設計模式,在總結命令模式時,說到命令模式支持事物的回退,而這個就是依靠的備忘錄模式來實現的。好了,備忘錄模式就總結至此。希望對大家有用。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久国产精品久久久久| 国产精品大片wwwwww| 久久免费精品视频| 91av视频在线播放| 麻豆一区二区在线观看| 98精品在线视频| 久久久久国产精品免费网站| 亚洲深夜福利视频| 日韩欧美亚洲成人| 欧美激情一区二区三区在线视频观看| 日韩在线观看免费网站| 亚洲一级黄色片| 国产日本欧美一区二区三区| 国产欧美一区二区| 亚洲片国产一区一级在线观看| 久久久久亚洲精品| 日韩中文字幕视频在线| 欧美自拍大量在线观看| 国产精品伦子伦免费视频| 欧美高清视频免费观看| 国产精品日日摸夜夜添夜夜av| 欧美成人免费在线视频| 亚洲最大福利网站| 亚洲成年人影院在线| 亚洲精品美女网站| 久久久久国产精品免费| 成人妇女免费播放久久久| 亚洲国产中文字幕在线观看| 日韩高清av一区二区三区| 国产亚洲在线播放| 久久综合色影院| 黄色一区二区在线| 亚洲色图偷窥自拍| 97免费中文视频在线观看| 亚洲欧美精品中文字幕在线| 午夜精品久久久久久99热软件| 亚洲精品av在线| 日韩电影免费观看在线| 中文字幕日韩电影| 91人人爽人人爽人人精88v| 色999日韩欧美国产| 欧美第一黄网免费网站| 69影院欧美专区视频| 日韩a**站在线观看| 久久夜精品va视频免费观看| 久久久国产精品亚洲一区| 国产美女91呻吟求| 亚洲精品在线看| 欧美亚洲另类激情另类| 国产一区二区久久精品| 色综合久久天天综线观看| 久久91亚洲精品中文字幕奶水| 成年无码av片在线| 国语自产精品视频在线看一大j8| 国产精品一区二区三区免费视频| 97超级碰碰碰| 欧美精品激情在线| 黑人巨大精品欧美一区二区免费| 91精品在线观看视频| 日韩av在线电影网| 久久久国产精品一区| 成人国产在线视频| 九九精品在线观看| 国产精品一区二区久久国产| 国产精品精品视频一区二区三区| 国产成人综合精品| 日韩第一页在线| 亚洲天堂免费观看| 国内伊人久久久久久网站视频| 亚洲国产精品资源| 国产精品久久久一区| 中文字幕av日韩| 亚洲色图日韩av| 欧美日韩国产一区在线| 亚洲欧美一区二区激情| 91精品国产综合久久久久久蜜臀| 日韩av在线免费看| 国产中文字幕亚洲| 日韩美女福利视频| 日韩精品中文在线观看| 国产精品香蕉av| 国产亚洲欧洲高清一区| 在线播放亚洲激情| 国产精品对白刺激| 51午夜精品视频| 亚洲午夜精品久久久久久性色| 国产精品九九久久久久久久| 日韩欧美在线免费观看| 日韩精品www| 国产精品亚洲一区二区三区| 免费97视频在线精品国自产拍| 欧美另类精品xxxx孕妇| 亚洲自拍偷拍色图| 黑人巨大精品欧美一区二区三区| 91久久在线观看| 岛国精品视频在线播放| 日韩少妇与小伙激情| 亚洲第一区在线| 97视频在线观看网址| 国产精品一香蕉国产线看观看| 伦伦影院午夜日韩欧美限制| 国产视频丨精品|在线观看| 亚洲欧洲美洲在线综合| 国产精品网站视频| 午夜精品在线观看| 精品久久久av| 欧美一区二区三区四区在线| 国产欧美精品一区二区三区-老狼| 欧美电影在线观看完整版| 精品精品国产国产自在线| 中文字幕精品www乱入免费视频| 国产精品久久久久av免费| 精品久久久久久久久久ntr影视| 操91在线视频| 欧美丰满少妇xxxxx| 日韩大片免费观看视频播放| 日本久久精品视频| 国产日韩精品综合网站| 日本sm极度另类视频| 国产精品久在线观看| 亚洲一区二区三区久久| 久久夜色精品国产| 成人免费观看49www在线观看| 久久全球大尺度高清视频| 九九久久久久久久久激情| 日韩成人xxxx| 精品女同一区二区三区在线播放| 久久综合九色九九| 亚洲美女性生活视频| 久久久久久久久久久久久久久久久久av| www.日韩.com| 久久精品久久久久久| 国产精品一区久久| 欧美乱妇40p| 国产精品免费视频xxxx| 亚洲精品720p| 美日韩精品视频免费看| 国产精品一区二区久久| 久久久精品在线观看| 尤物精品国产第一福利三区| 亚洲另类xxxx| 欧美片一区二区三区| 91av在线免费观看| 国产精品久久久久久久久免费看| 91国产美女在线观看| 日av在线播放中文不卡| 夜夜嗨av一区二区三区免费区| 日本道色综合久久影院| 91在线视频成人| 成人在线免费观看视视频| 欧美在线视频观看| 日韩精品亚洲精品| 欧美高清视频在线| 欧美最顶级丰满的aⅴ艳星| 久久久之久亚州精品露出| 亚洲高清色综合| 亚洲天堂第二页| 欧美大奶子在线| 日本aⅴ大伊香蕉精品视频| 成人av在线天堂| 欧美日韩国产中字| 国模私拍视频一区| 日本精品免费一区二区三区| 日韩欧美在线视频日韩欧美在线视频|