C++設計形式之備忘錄形式。本站提示廣大學習愛好者:(C++設計形式之備忘錄形式)文章只能為提供參考,不一定能成為您想要的結果。以下是C++設計形式之備忘錄形式正文
媒介
又到歲尾了,也靜不下心來寫代碼了,年夜家都很急躁;翻出經典的《仙劍奇俠傳》玩一會;又要打年夜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類能力停止備忘錄的讀取和設置。因為備忘錄重要是用於對對象的狀況停止備份,完成了撤消操作,假如對象的狀況數據很年夜許多時,在停止備忘時,就會很占用資本,這個是我們在現實開辟時須要斟酌的器械。聯合之前的設計形式,在總結敕令形式時,說到敕令形式支撐事物的回退,而這個就是依附的備忘錄形式來完成的。好了,備忘錄形式就總結至此。願望對年夜家有效。