程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [設計模式]備忘錄

[設計模式]備忘錄

編輯:C++入門知識

我們經常遇到將一個類的狀態恢復到歷史版本的需求。比如一個記事本,想保存一個上N個狀態,通過Ctrl+Z可以恢復此前編輯內容。備忘錄就非常適合這種場景。此時發起者類,希望能夠將自身狀態保留在某處,而且不希望過多的暴露細節。為了上述目的,發起者會在某個時刻通過new出一個備忘類對象,並將該對象托管給管理者類。然後需要恢復狀態時,又從管理者類中獲取具體狀態,將自身恢復到某個狀態。

為了保持封裝性,備忘錄一般除了將自己暴露給發起者外(或者可以認為是發起者將自己狀態暴露給了備忘類),不為外部類提供任何訪問狀態相關接口。C++中這個通常是通過將自己所有接口都改成private(包括構造函數),然後將發起者設為自己的友元類來實現。

寫了個demo,可以支持多個版本:


[cpp]
/***************************************************************************
 * 
 * Copyright (c) 2013 itegel.com, Inc. All Rights Reserved
 * 
 **************************************************************************/ 
  
  
  
/**
 * @file test_memento.cpp
 * @author itegel
 * @date 2013/06/08 11:29:08
 * @brief 
 *  
 **/ 
 
#include <string>  
#include <map>  
#include <iostream>  
using namespace std; 
 
class State{ 
    public: 
        int version; 
        string content; 
}; 
 
class Memento{ 
    public: 
    private: 
        friend class NoteBook; 
        Memento(State state) : _state(state){} 
        ~Memento(){} 
 
        State * GetState(){ 
            return &_state; 
        } 
        void SetState(State state){ 
            _state = state; 
        } 
        State _state; 
}; 
 
//originator  
class NoteBook{ 
    public: 
        NoteBook(int version, string content){ 
            _state.version = version; 
            _state.content = content;             
        } 
         
        NoteBook(State & state):_state(state){ 
                     
        } 
         
        void SetMemento(Memento * mem){ 
            _state = mem->_state; 
        } 
 
        Memento * GetMemento(){ 
            return new Memento(_state); 
        } 
 
        void SetState(int version, string content){ 
            _state.version = version; 
            _state.content = content; 
        } 
         
        int GetVersion(){ 
            return _state.version; 
        } 
 
        void PrintState(){ 
            cout<<"Note:\n\tversion:\t"<<_state.version<<endl<<"\tcontent:\t"<<_state.content<<endl; 
        } 
 
    private: 
        State _state; 
}; 
 
 
class CareTaker{ 
    public: 
        CareTaker(){} 
        void Save(int id, Memento * mem){ 
            _memento_map[id] = mem; 
        } 
        Memento * GetMemento(int id){ 
            return _memento_map[id]; 
        } 
    private: 
        map<int, Memento *> _memento_map; 
}; 
 
int main(){ 
    NoteBook my_note(0, ""); 
    CareTaker care_taker; 
 
    my_note.PrintState(); 
    cout<<"Save State 0!"<<endl; 
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento()); 
 
    cout<<endl<<"Edit for 1st time!"<<endl; 
    my_note.SetState(1, "Hello world!"); 
    my_note.PrintState(); 
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento()); 
     
    cout<<endl<<"Edit for 2nd time!"<<endl; 
    my_note.SetState(2, "Hello World! It is the 2nd version!"); 
    my_note.PrintState(); 
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento()); 
     
    cout<<endl<<"Edit for 3rd time!"<<endl; 
    my_note.SetState(3, "Hello Itegel! It is the 3rd version!"); 
    my_note.PrintState(); 
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento()); 
 
 
    cout<<endl<<"Restore 2nd version:"<<endl; 
    Memento * mem = care_taker.GetMemento(2); 
    my_note.SetMemento(mem); 
    my_note.PrintState(); 
     
    cout<<endl<<"Restore 0 version:"<<endl; 
    mem = care_taker.GetMemento(0); 
    my_note.SetMemento(mem); 
    my_note.PrintState(); 
 
    return 0; 

/***************************************************************************
 *
 * Copyright (c) 2013 itegel.com, Inc. All Rights Reserved
 *
 **************************************************************************/
 
 
 
/**
 * @file test_memento.cpp
 * @author itegel
 * @date 2013/06/08 11:29:08
 * @brief
 * 
 **/

#include <string>
#include <map>
#include <iostream>
using namespace std;

class State{
    public:
        int version;
        string content;
};

class Memento{
    public:
    private:
        friend class NoteBook;
        Memento(State state) : _state(state){}
        ~Memento(){}

        State * GetState(){
            return &_state;
        }
        void SetState(State state){
            _state = state;
        }
        State _state;
};

//originator
class NoteBook{
    public:
        NoteBook(int version, string content){
            _state.version = version;
            _state.content = content;           
        }
       
        NoteBook(State & state):_state(state){
                   
        }
       
        void SetMemento(Memento * mem){
            _state = mem->_state;
        }

        Memento * GetMemento(){
            return new Memento(_state);
        }

        void SetState(int version, string content){
            _state.version = version;
            _state.content = content;
        }
       
        int GetVersion(){
            return _state.version;
        }

        void PrintState(){
            cout<<"Note:\n\tversion:\t"<<_state.version<<endl<<"\tcontent:\t"<<_state.content<<endl;
        }

    private:
        State _state;
};


class CareTaker{
    public:
        CareTaker(){}
        void Save(int id, Memento * mem){
            _memento_map[id] = mem;
        }
        Memento * GetMemento(int id){
            return _memento_map[id];
        }
    private:
        map<int, Memento *> _memento_map;
};

int main(){
    NoteBook my_note(0, "");
    CareTaker care_taker;

    my_note.PrintState();
    cout<<"Save State 0!"<<endl;
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento());

    cout<<endl<<"Edit for 1st time!"<<endl;
    my_note.SetState(1, "Hello world!");
    my_note.PrintState();
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento());
   
    cout<<endl<<"Edit for 2nd time!"<<endl;
    my_note.SetState(2, "Hello World! It is the 2nd version!");
    my_note.PrintState();
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento());
   
    cout<<endl<<"Edit for 3rd time!"<<endl;
    my_note.SetState(3, "Hello Itegel! It is the 3rd version!");
    my_note.PrintState();
    care_taker.Save(my_note.GetVersion(), my_note.GetMemento());


    cout<<endl<<"Restore 2nd version:"<<endl;
    Memento * mem = care_taker.GetMemento(2);
    my_note.SetMemento(mem);
    my_note.PrintState();
   
    cout<<endl<<"Restore 0 version:"<<endl;
    mem = care_taker.GetMemento(0);
    my_note.SetMemento(mem);
    my_note.PrintState();

    return 0;
}


執行結果:


[plain]
Note: 
    version:    0 
    content:     
Save State 0! 
 
Edit for 1st time! 
Note: 
    version:    1 
    content:    Hello world! 
 
Edit for 2nd time! 
Note: 
    version:    2 
    content:    Hello World! It is the 2nd version! 
 
Edit for 3rd time! 
Note: 
    version:    3 
    content:    Hello Itegel! It is the 3rd version! 
 
Restore 2nd version: 
Note: 
    version:    2 
    content:    Hello World! It is the 2nd version! 
 
Restore 0 version: 
Note: 
    version:    0 
    content:     

Note:
 version: 0
 content: 
Save State 0!

Edit for 1st time!
Note:
 version: 1
 content: Hello world!

Edit for 2nd time!
Note:
 version: 2
 content: Hello World! It is the 2nd version!

Edit for 3rd time!
Note:
 version: 3
 content: Hello Itegel! It is the 3rd version!

Restore 2nd version:
Note:
 version: 2
 content: Hello World! It is the 2nd version!

Restore 0 version:
Note:
 version: 0
 content: 

 

備忘錄模式使用場景應該比較固定,但是其實現可以很靈活。主要思想就是將自己的狀態托管給一個其他類,但是又不想過多的暴露自身信息,從而引入了備忘錄類。變化的地方應該是狀態成員的變化吧。此時只需要修改State類就好,其他其實可以做到不用修改(除了發起者關於這個新增狀態信息的維護)。

 


P.S. 到這兒23個設計模式中行為模式都寫過一些demo了。好久沒抽空寫東西了,發現其實寫代碼都有些生疏了。
這些天一直抽空寫一些demo,理解還不夠深,但是代碼都是自己一行一行敲進去的。這樣體會會深一些吧。其實很多時候,還是需要跟實際項目結合,理解會更深一些。個人體會是,程序員多寫代碼才是王道。


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved