1. 程式人生 > >設計模式(二十)——備忘錄模式

設計模式(二十)——備忘錄模式

設計模式 備忘錄模式

設計模式(二十)——備忘錄模式

一、備忘錄模式

1、備忘錄模式簡介

備忘錄模式在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在對象之外保存這個狀態,以後就可將對象恢復到原先保存的狀態

技術分享

2、備忘錄模式角色

發起人Originator:負責創建一個Memento,用以記錄當前時刻Originator的內部狀態,並可使用

Memento恢復內部狀態。Originator可根據需要決定Memento存儲Originator的哪些內部狀態。Originator記錄當前時刻的內部狀態,負責定義哪些屬於備份範圍的狀態,負責創建和恢復備忘錄數據。

備忘錄Memento:負責存儲Originator對象的內部狀態,並可防止Originator以外的其他對象訪問備忘錄Memento。備忘錄有兩個接口,Caretaker只能看到備忘錄的窄接口,Caretaker只能將備忘錄傳遞給其他對象。Originator能夠看到一個寬接口,允許Originator訪問返回到先前狀態所需的所有數據。Memento負責存儲發起人對象的內部狀態,在需要的時候提供發起人需要的內部狀態。

管理者Caretaker:負責保存好備忘錄Memento不能對備忘錄的內容進行操作或檢查。Caretaker對備忘錄進行管理,保存和提供備忘錄。

Memento模式中封裝的是需要保存的狀態當需要恢復的時候才取出來進行恢復Memento角色有兩個接口:窄接口和寬接口寬接口是一般意義上的接口把對外的接口作為public成員而窄接口把接口作為private成員而把需要訪問接口函數的類作為Memento類的友元類,即窄接口只暴露給了對接口感興趣的類而不是暴露在外部

Memento模式比較適用於功能比較復雜的,但需要維護或記錄歷史屬性的類,或者需要保存的屬性只是眾多屬性中的一小部分時,

Originator可以根據保存的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;
}



本文出自 “生命不息,奮鬥不止” 博客,謝絕轉載!

設計模式(二十)——備忘錄模式