備忘錄模式 | Memento Pattern

Posted by Ian Tsai on Sunday, October 4, 2020

本系列文章同步分享於IT邦幫忙第12屆鐵人賽


Design Pattern 系列文章導讀


Design Pattern可以說是開發上大家都會遇到的一個課題, 這系列文會從Design Principles、各種design pattern到最後的Anti-Patterns & Code Smells介紹下去,讓我們可以更了解各種pattern的使用時機與場合。 預計目標主題如下,若有哪部分不熟的章節可以直接點進去看
註:可以利用Online Java Compiler IDE

  1. 設計模式 - 入門篇
  2. 設計模式 - 原則篇 | Design Principles
  3. 設計模式 - 創建型模型篇 | Creational Patterns
  4. 設計模式 - 結構型模型篇 | Structural Patterns
  5. 設計模式 - 行為型模型篇 | Behavioural Patterns
  6. 設計模式 - 番外篇
  • 定義


在不破壞封裝的前提下,儲存一個物件的某個狀態,以便於需要的時候將物件恢復到原先儲存的狀態。

如果人生有後悔藥多好。其實生活中也有許多類似備忘錄模式的案例,如工作時,誤刪了一筆資料,可以使用ctrl+z拯救被刪除的資料。又或是玩遊戲要都會存擋,這樣死了就不需要重頭玩。備忘錄模式就是紀錄一個物件的內部狀態,當後悔時可以撤銷現在的操作,回復到先前的狀態。備忘錄模式是一個可以記錄物件內部狀態,當需要使用時取消目前的操作,回復到原先狀態的一種模式。

  • Memento Pattern 成員


name description
Originator(發起人) 紀錄目前的內部狀態,提供建立備忘錄及回復備忘錄狀態的功能,可以訪問備忘錄內所有訊息。
Memento(備忘錄) 保存發起人的內部狀態,在需要的時候提供給發起人。
Caretaker(管理者) 管理、保存及讀取備忘錄的功能,但不能對備忘錄的內容進行訪問及修改。
  • Memento Pattern 實作


相信大部分男性都有當兵的經驗,大家最常聽到的一句話: 回復上一動。 我們就用班長的回復上一動來實作備忘錄模式。

// 備忘錄,有保存狀態及取出狀態兩個方法。
class Memento { 
    private String state; 
    public Memento(String state) { 
        this.state = state; 
    }     
    public void setState(String state) { 
        this.state = state; 
    }
    public String getState() { 
        return state; 
    }
}
// 發起人,也就是班長,負責對部隊發號司令。
class Originator { 
    private String state;     
    public void setState(String state) {
        System.out.println(state + "!");
        this.state = state; 
    }
    public String getState() { 
        return state; 
    }
    public Memento createMemento() {  // 建立備忘錄
        return new Memento(state); 
    } 
    public void restoreMemento(Memento m) {  // 回復上一個狀態
        System.out.println("班長:幹什麼!回復上一動!");
        this.setState(m.getState()); 
    } 
}
// 管理者,保存備忘錄及取得備忘錄
class Caretaker { 
    private Memento memento;       
    public void setMemento(Memento m) { 
        memento = m; 
    }
    public Memento getMemento() { 
        return memento; 
    }
}
public class MementoPattern {
    public static void main(String[] args) {
        Originator or = new Originator();
        Caretaker cr = new Caretaker();       
        or.setState("稍息!!"); 
        System.out.println("---初始狀態:" + or.getState());           
        cr.setMemento(or.createMemento()); //保存      
        or.setState("置板凳!!"); 
        System.out.println("---新的狀態:" + or.getState());     
        or.restoreMemento(cr.getMemento()); //回復
        System.out.println("---回復狀態:" + or.getState());
    }
}

output

稍息!!!
---初始狀態:稍息!!
置板凳!!!
---新的狀態:置板凳!!
班長:幹什麼!回復上一動!
稍息!!!
---回復狀態:稍息!!
  • 小結


Memento Pattern的目標

在不破壞封裝的前提下,儲存一個物件的某個狀態,以便於需要的時候將物件恢復到原先儲存的狀態。

Memento Pattern的成員
Originator(發起人):紀錄目前的內部狀態,提供建立備忘錄及回復備忘錄狀態的功能,可以訪問備忘錄內所有訊息。
Memento(備忘錄):保存發起人的內部狀態,在需要的時候提供給發起人。
Caretaker(管理者):管理、保存及讀取備忘錄的功能,但不能對備忘錄的內容進行訪問及修改。
Memento Pattern的優缺點
優點
1. 提供可回復的機制,用戶可以將狀態回復到以前某的狀態。
2. 實現內部狀態的封裝,除了建立的發起人,其於物劍不可以訪問。
3. 簡化發起人,不需要管理及保存撞奈的備份,所有的訊息都由管理者管理,符合單一職責原則。
缺點
1. 資源消耗大。 
Memento Pattern的使用時機
1. 需要保存及回覆的時候,如遊戲存擋。
2. 需要可以回復操作,如Ctrl+Z 。
  • 範例程式碼


範例:Memento Pattern 實作

  • References


  • 備忘錄模式 Memento
  • 备忘录模式(详解版)