天天看點

備忘錄模式 Memento

“狀态變化”模式

  • 在元件建構過程中,某些對象的狀态經常面臨變化,如何對這些變化進行有效的管理?同時又維持高層子產品的穩定?“狀态變化"模式為這一問題提供了一種解決方案。
  • 典型模式
  1. State
  2. Memento

動機(Motivation)

  • 在軟體建構過程中,某些對象的狀态在轉換過程中,可能由于某種需要,要求程式能夠回溯到對象之前處于某個點時的狀态。如果使用一些公有接口來讓其他對象得到對象的狀态,便會暴露對象的細節實作。
  • 如何實作對象狀态的良好儲存與恢複?但同時又不會是以而破壞對象本身的封裝性。

模式定義

在不破壞封裝性的前提下,捕獲一個對象的内部狀态,并在該對象之外儲存這個狀态。這樣以後就可以将該對象恢複到原先儲存的狀态。——《設計模式》GoF

// 原理思想很簡單,具體的實作有可能是很複雜的,儲存一次或儲存N次。

示例

#include <iostream>
#include <string>

using namespace std;


class Memento
{
    string state;
    //...
public:
    Memento(const string & s) : state(s) {}
    string getState() const { return state; }
    void setState(const string & s) { state = s; }
};


// 這個是穩定的,不破壞它的封裝
class Originator
{
    string state;
    //....
public:
    Originator() {}
    Memento createMomento() {
        Memento m(state); // 現實實作中,内部有可能非常複雜。
        return m;
    }
    void setMomento(const Memento & m) {
        state = m.getState();
    }
    void showState() {
        cout << state << endl;
    }
    void setState(string str) {
        state = str;
    }
};


int main()
{
    Originator orginator;
    orginator.setState("晴天");
    orginator.showState();

    //捕獲對象狀态,存儲到備忘錄   拍個快照
    Memento mem = orginator.createMomento();

    //... 改變orginator狀态
    orginator.setState("晴轉多雲");
    orginator.showState();
    orginator.setState("西北雨");
    orginator.showState();

    //從備忘錄中恢複
    orginator.setMomento(mem);
    orginator.showState();

    getchar();
    return 0;
}      

輸出:

晴天
晴轉多雲
西北雨
晴天      

類圖

備忘錄模式 Memento

要點總結

  • 備忘錄(Memento)存儲原發器(Originator)對象的内部狀态,在需要時恢複原發器狀态。
  • Memento模式的核心是資訊隐藏,即Originator需要向外接隐藏資訊,保持其封裝性。但同時又需要将狀态保持到外界(Memento)。
  • 由于現代語言運作時(如C#、Java等)都具有相當的對象序列化支援,是以往往采用效率較高、又較容易正确實作的序列化方案來實作Memento模式。//是以,這個設計模式有點過時。

今天,語言和架構提供了我們非常友善和高效的方式,這個模式在 94 年。

繼續閱讀