設計模式之備忘錄模式

2018-09-22 22:35:23ios

備忘錄模式

  備忘錄(Memento):在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。這樣之後就可將該對象恢復到原來保存的狀態。設計模式

備忘錄模式UML類圖

Originator(發起人):負責建立一個備忘錄Memento,用以記錄當前時刻它的內部狀態,並可使用備忘錄恢復內部狀態。Originator可根據須要決定Memento存儲Originator的哪些內部狀態。ide

Memento(備忘錄):負責存儲Originator對象的內部狀態,並可防止Originator之外的其它對象訪問備忘錄Memento。備忘錄有兩個接口,Cartaker只能看到備忘錄的窄接口,它只能將備忘錄傳遞給其它對象。Originator能看到一個寬接口,容許它訪問返回到先前狀態所需的全部數據。函數

Caretaker(管理者):負責保存好備忘錄Memento,不能對備忘錄的內容進行操做或者檢查。spa

優缺點

優勢:設計

  1.提供了一種狀態恢復機制,把要保存的細節封裝在了Memento中,使用戶可以方便的回到某個歷史狀態,若是須要更改保存的細節,也不會對客戶端產生影響。rest

  2.實現了信息的封裝,使用戶不須要關心保存信息的細節。code

缺點:對象

  1.角色狀態須要完整存儲到備忘錄對象中,若是狀態數據不少很大,那麼在資源消耗上,備忘錄對象會很是消耗內存。blog

適用場景:

  Memento模式比較適用於功能比較複雜的,但須要維護或記錄屬性歷史的類,或者須要保存的屬性只是衆多屬性中的一小部分時,Originator能夠根據保存的Memento信息還原到前一狀態,有時一些對象的內部信息必須保存在對象之外的地方,可是必須由對象本身讀取,這是使用備忘錄能夠把複雜的對象內部信息對其它的對象屏蔽起來。做用是,當角色的狀態改變的時候,有可能這個狀態無效,這時候就可使用暫時存儲起來的備忘錄將狀態復原。

代碼示例

  (都是《大話設計模式》這本書的內容呀)背景:遊戲進度備忘。假設咱們須要保存的遊戲角色的屬性有:藍量、血量、以及攻擊力、防護力四個。

1.Originator類。打遊戲的時候只有角色本身擁有恢復存檔和保存進度的能力

#ifndef ORIGINATOR_H_
#define ORIGINATOR_H_
//這個類在本例中是遊戲角色類
//假設你正在玩某個遊戲,回憶一下,具備存檔和讀取存檔數據的是否是隻有你的遊戲角色呢?
#include "Memento.h"
#include <string>
#include <iostream>

class Originator
{
public:
    Memento createMemento()
    {
    return Memento(m_iLifeValues,m_iMP,m_iATK,m_iDef);    //建立一個備忘錄,將當前須要保存的信息導入,並實例化出一個Memento對象
    }
    //從備忘錄中恢復存檔(爲何須要這個函數呢,你想一下,你在存檔以後,下機了,下次再登陸進入遊戲,要恢復存檔,數據必然要從某個地方讀入,因此這個函數是必須的
    void restoreMemento(Memento objMemento)
    {
    m_iLifeValues = objMemento.getLifeValues();
        m_iMP = objMemento.getMP();
        m_iATK = objMemento.getATK();
        m_iDef = objMemento.getDef();
    }
    
    //顯示屬性值
    void show() const
    {
    std::cout << "Name: " << m_strRoleName << " LifeValues:" << m_iLifeValues << " MP:" << m_iMP << " ATK:" << m_iATK << " Def:" << m_iDef <<std::endl;
    }
    //設置屬性的初始值
    void setInit(const int iLifeValues,const int iMP,const int iATK, const int iDef)  
    {
    m_iLifeValues = iLifeValues;
        m_iMP = iMP;
    m_iATK = iATK;
    m_iDef = iDef;
    }
    
    //和Boss玩玩,給你一下各項屬性減去100(隨便寫的,因此結果可能出現負值)
    //返回值爲false,則表示Game over
    bool beatAMonster()
    {
    m_iLifeValues -=100;
        m_iMP -= 100;
    m_iATK -=100;
    m_iDef -=100;
    if(0>= m_iLifeValues)
    {
        return false;
        }
    return true;
    }
    
    Originator(const std::string strRoleName) : m_strRoleName(strRoleName){};
    ~Originator() = default;
private:
    //遊戲角色的屬性:生命值、魔法值、攻擊力、防護力
    int m_iLifeValues{0};    //生命值
    int m_iMP{0};    //魔法值
    int m_iATK{0};    //攻擊力
    int m_iDef{0};    //防護值
    std::string m_strRoleName;
};
#endif
Originator

2.Mementor類。備忘錄,用於保存Originator類內部狀態的外部類

#ifndef MEMENTO_H_
#define MEMENTO_H_
//備忘錄類,負責保存屬性
class Memento
{
public:
    //讀取存檔生命值
    int getLifeValues() const
    {
    return m_iLifeValues;
    }
    //讀取魔法存檔值
    int getMP() const
    {
    return m_iMP;
    }
    //讀取攻擊力存檔
    int getATK() const
    {
    return m_iATK;
    }
    //讀取防護力存檔
    int getDef() const
    {
    return m_iDef;
    }
    Memento(const int iLifeValues,const int iMP,const int iATK,const int iDef):m_iLifeValues(iLifeValues),m_iMP(iMP),m_iATK(iATK),m_iDef(iDef){};
    Memento(const Memento& objMemento)
    {
    m_iLifeValues = objMemento.getLifeValues();
    m_iMP = objMemento.getMP();
    m_iATK = objMemento.getATK();
        m_iDef = objMemento.getDef();
    }
    Memento() = default;
    ~Memento() = default;
private:
    int m_iLifeValues{0};    //生命值
    int m_iMP{0};    //魔法值
    int m_iATK{0};    //攻擊力
    int m_iDef{0};    //防護力
};
#endif
Memento

3.Caretaker類。備忘錄的管理類。

#ifndef CARETAKER_H_
#define CARETAKER_H_
//管理者,這個類用來管理備忘錄,它的做用,就是從加載備忘錄的內容,將其恢復到某個對象

#include "Memento.h"

class Caretaker
{
public:
    //設置備忘錄
    void setMemento(Memento objMemento)
    {
    m_Memento = objMemento;
    }
    Memento getMemento()
    {
    return m_Memento;
    }
private:
    Memento m_Memento;        //持有一個備忘錄對象,它是Caretaker進行備忘錄管理的關鍵
};
#endif
Caretaker

4.client

#include "Caretaker.h"
#include "Originator.h"

using namespace std;

int main(int argc,char *argv[])
{
    //建立一個遊戲角色
    Originator objOriginator("ChongLou");
    //設置初始屬性
    objOriginator.setInit(100,100,100,100);
    //保存初始狀態
    Caretaker objCaretaker;
    objCaretaker.setMemento(objOriginator.createMemento());
    //顯示初始狀態
    objOriginator.show();
    //開始打怪
    objOriginator.beatAMonster();
    //顯示打怪後的屬性
    objOriginator.show();
    //加載存檔
    objOriginator.restoreMemento(objCaretaker.getMemento());
    //顯示加載存檔後的屬性
    objOriginator.show();
    return(1);
}
Client
相關文章
相關標籤/搜索