設計模式(二十)——備忘錄模式
設計模式(二十)——備忘錄模式
一、備忘錄模式
1、備忘錄模式簡介
備忘錄模式在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在對象之外保存這個狀態,以後就可將對象恢復到原先保存的狀態。
2、備忘錄模式角色
發起人Originator:負責創建一個Memento,用以記錄當前時刻Originator的內部狀態,並可使用
備忘錄Memento:負責存儲Originator對象的內部狀態,並可防止Originator以外的其他對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到備忘錄的窄接口,Caretaker只能將備忘錄傳遞給其他對象。Originator能夠看到一個寬接口,允許Originator訪問返回到先前狀態所需的所有數據。Memento負責存儲發起人對象的內部狀態,在需要的時候提供發起人需要的內部狀態。
管理者Caretaker:負責保存好備忘錄Memento,不能對備忘錄的內容進行操作或檢查。Caretaker對備忘錄進行管理,保存和提供備忘錄。
Memento模式中封裝的是需要保存的狀態,當需要恢復的時候才取出來進行恢復。Memento角色有兩個接口:窄接口和寬接口。寬接口是一般意義上的接口,把對外的接口作為public成員,而窄接口把接口作為private成員,而把需要訪問窄接口函數的類作為Memento類的友元類,即窄接口只暴露給了對窄接口感興趣的類,而不是暴露在外部。
Memento模式比較適用於功能比較復雜的,但需要維護或記錄歷史屬性的類,或者需要保存的屬性只是眾多屬性中的一小部分時,
如果在某個系統中使用命令模式時,需要實現命令的撤銷功能,那麽命令模式可以使用備忘錄模式來存儲可撤銷操作的狀態。
3、備忘錄模式優缺點
備忘錄模式的優點:
A、當發起人中的狀態改變時,有可能是個錯誤的改變,使用備忘錄模式就可以把錯誤的改變還原。
B、備份的狀態是保存在發起人之外的,發起人就不需要對各個備份的狀態進行管理。
備忘錄模式的缺點:
在實際應用中,備忘錄模式都是多狀態和多備份的,發起人角色的狀態需要存儲到備忘錄對象中,對資源的消耗是比較嚴重的。
4、備忘錄模式使用場景
如果有需要提供回滾操作的需求,使用備忘錄模式非常適合,比如JDBC的事務操作,文本編輯器的Ctrl+Z恢復等。
二、備忘錄模式實現
Originator發起人:
#ifndef ORIGINATOR_H #define ORIGINATOR_H #include "Memento.h" #include <iostream> using namespace std; //Originator發起人 class Originator { public: Originator(const string& state) { m_state = state; } Memento* createMemento() { return new Memento(m_state); } void restoreToMemento(Memento* memento) { m_state = memento->getState(); } void setState(const string& state) { m_state = state; } string getState() { return m_state; } void show() { cout << m_state << endl; } private: string m_state; }; #endif // ORIGINATOR_H
Memento備忘錄:
#ifndef MEMENTO_H #define MEMENTO_H #include <string> using namespace std; //Memento class Memento { private: //Originator為friend類,可以訪問內部信息,但是其他類不能訪問 friend class Originator; Memento(const string& state) { m_state = state; } void setState(const string& state) { m_state = state; } string getState() { return m_state; } private: string m_state; }; #endif // MEMENTO_H
Caretaker管理者:
#ifndef CARETAKER_H #define CARETAKER_H #include "Memento.h" //Caretaker管理者 class Caretaker { public: void setMemento(Memento* memento) { m_pMemento = memento; } Memento* getMemento() { return m_pMemento; } private: Memento* m_pMemento; }; #endif // CARETAKER_H
客戶調用程序:
#include "Memento.h" #include "Originator.h" #include "Caretaker.h" int main() { //創建初始狀態為old Originator* originator = new Originator("old"); originator->show(); //建立並保存Memento Caretaker* taker = new Caretaker(); taker->setMemento(originator->createMemento()); //改變狀態為new originator->setState("new"); originator->show(); //恢復狀態 originator->restoreToMemento(taker->getMemento()); originator->show(); return 0; }
三、備忘錄模式實例
玩遊戲時都會保存進度,所保存的進度以文件的形式存在。下次就可以繼續玩,而不用從頭開始。進度其實就是遊戲的內部狀態,而文件是在遊戲之外保存狀態。下次可以從文件中讀入保存的進度,從而恢復到原來的狀態。
GameRole發起人:
#ifndef GAMEROLE_H #define GAMEROLE_H #include "Memento.h" #include <iostream> using namespace std; //發起人 class GameRole { public: void initState() { m_vitality = 100; m_attack = 100; m_defense = 100; } void fight() { m_vitality -= 30; m_attack -= 50; m_defense -= 40; } void setVitality(unsigned int vitality) { m_vitality = vitality; } unsigned int getVitality() { return m_vitality; } void setAttack(unsigned int attack) { m_attack = attack; } unsigned int getAttack() { return m_attack; } void setDefense(unsigned int defense) { m_defense = defense; } unsigned int getDefense() { return m_defense; } void show() { cout << "State at current:" << endl; cout << " Vitality: " << m_vitality << endl; cout << " Attack: " << m_attack << endl; cout << " Defense: " << m_defense << endl; } //創建備忘錄 Memento* createMemento() { return new Memento(m_vitality, m_attack, m_defense); } //從備忘錄恢復狀態 void restoreFromMemento(Memento* memento) { m_vitality = memento->getVitality(); m_attack = memento->getAttack(); m_defense = memento->getDefense(); } private: unsigned int m_vitality;//生命力 unsigned int m_attack;//攻擊力 unsigned int m_defense;//防禦力 }; #endif // GAMEROLE_H
Memento備忘錄:
#ifndef MEMENTO_H #define MEMENTO_H //備忘錄 class Memento { friend class GameRole; private: Memento(unsigned int vitality,unsigned int attack,unsigned int defense) { m_vitality = vitality; m_attack = attack; m_defense = defense; } void setVitality(unsigned int vitality) { m_vitality = vitality; } unsigned int getVitality() { return m_vitality; } void setAttack(unsigned int attack) { m_attack = attack; } unsigned int getAttack() { return m_attack; } void setDefense(unsigned int defense) { m_defense = defense; } unsigned int getDefense() { return m_defense; } private: unsigned int m_vitality; unsigned int m_attack; unsigned int m_defense; }; #endif // MEMENTO_H
CareTaker管理者:
#ifndef CARETAKER_H #define CARETAKER_H #include "Memento.h" #include <iostream> //管理者 class CareTaker { public: ~CareTaker() { if(m_pMemento != NULL) { delete m_pMemento; m_pMemento = NULL; } } Memento* GetMemento() { return m_pMemento; } void SetMemento(Memento* memento) { m_pMemento = memento; } private: Memento* m_pMemento; }; #endif // CARETAKER_H
客戶調用程序:
#include "GameRole.h" #include "CareTaker.h" #include "Memento.h" int main() { //攻擊之前 GameRole* role = new GameRole(); role->initState(); role->show(); //保存進度 CareTaker* taker=new CareTaker(); taker->SetMemento(role->createMemento()); //開戰,損耗嚴重 role->fight(); role->show(); //恢復開戰前狀態 role->restoreFromMemento(taker->GetMemento()); role->show(); delete role; delete taker; return 0; }
本文出自 “生命不息,奮鬥不止” 博客,謝絕轉載!
設計模式(二十)——備忘錄模式