備忘錄模式(Memento Pattern)保存一個對象的某個狀態,以便在適當的時候恢復對象。備忘錄模式屬于行為型模式。
介紹
所謂備忘錄模式就是在不破壞封裝的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態,這樣可以在以后將對象恢復到原先保存的狀態。
備忘錄模式(Memento Pattern)又叫做快照模式(Snapshot Pattern),簡單理解為對當前對象的狀態進行備份,當使用時將備份釋放,覆蓋指定的對象。
何時使用
很多時候我們總是需要記錄一個對象的內部狀態,這樣做的目的就是為了允許用戶取消不確定或者錯誤的操作,能夠恢復到他原先的狀態,使得他有"后悔藥"可吃。以單機游戲進度的保存為例,當通關進行到某個場景,需要攻略boss的時候,通常會將游戲角色的狀態存儲起來,如果在boss大戰中失敗了沒用通關,則會進行讀檔操作,利用備忘錄恢復到攻略boss之前的狀態;又或是我們在使用word文檔編輯時,假如有一步操作錯誤想要撤銷時,就會使用word提供的撤銷功能,使編輯恢復到操作之前的狀態。
設計
那么我們怎么來通過C語言來設計一個備忘錄模式呢?
以文本編輯為例,當我們編輯文檔通常會有一個撤銷功能,在使用撤銷功能時,會有一個相應的撤銷動作。數據結構定義兩部分:撤銷的數據、恢復的操作。
typedef struct _Action
{
int type;
struct _Action* next;
void* pData;
void (*process)(void* pData);
}Action;
對應的還需要有創建的函數和恢復的函數,作為撤銷動作的管理者應該包括
typedef struct _Organizer
{
int number;
Action* pActionHead;
Action* (*create)();
void (*restore)(struct _Organizer* pOrganizer);
}Organizer;
數據恢復
void restore(struct _Organizer* pOrganizer)
{
Action* pHead;
assert(NULL != pOrganizer);
pHead = pOrganizer->pActionHead;
pHead->process(pHead->pData);
pOrganizer->pActionHead = pHead->next;
pOrganizer->number --;
free(pHead);
return;
}
以上就是備忘錄模式的核心了,實現了備份、撤銷、恢復動作。
備忘錄模式的優點和缺點
備忘錄模式的優點
1.有時一些發起人對象的內部信息必須保存在發起人對象以外的地方,但是必須要由發起人對象自己讀取,這時,使用備忘錄模式可以把復雜的發起人內部信息對其他的對象屏蔽起來,從而可以恰當地保持封裝的邊界。
2.當發起人角色的狀態改變的時候,有可能這個狀態無效,這時候就可以使用暫時存儲起來的備忘錄將狀態復原。
備忘錄模式的缺點
1.如果發起人角色的狀態需要完整地存儲到備忘錄對象中,那么在資源消耗上面備忘錄對象會很昂貴。
2.當負責人角色將一個備忘錄存儲起來的時候,負責人可能并不知道這個狀態會占用多大的存儲空間,從而無法提醒用戶一個操作是否很昂貴。
3.當發起人角色的狀態改變的時候,有可能這個協議無效。如果狀態改變的成功率不高話,不如采取“假如”協議模式。