cover

你改了半天的文件,結果改爛了想回到一小時前的版本。沒有存檔?那就完蛋了。有存檔?那你其實就在用 Memento Pattern。

先講結論

Memento Pattern 有三個角色:

  • Originator:被保存狀態的物件(你正在編輯的文件)
  • Memento:狀態快照(存檔點)
  • Caretaker:管理快照的人(存檔管理員,只保管不偷看內容)

重點是 Caretaker 拿到的是一個封裝好的快照,它不知道也不需要知道裡面存了什麼。封裝不被破壞。

classDiagram
    class Originator {
        -state : any
        +saveToMemento() Memento
        +restoreFromMemento(memento) void
    }
    class Memento {
        -state : any
        -timestamp : Date
        +getState() any
    }
    class Caretaker {
        -mementos : Memento[]
        +addMemento(memento) void
        +getMemento(index) Memento
    }
    Originator ..> Memento : 建立快照
    Caretaker o-- Memento : 保管歷史

實戰:簡易版本控制

Memento 模式:保存快照與回復狀態

class Memento {
    constructor(state) {
        this.state = state;
        this.timestamp = new Date();
    }
    getState() { return this.state; }
}
 
class Originator {
    constructor() { this.state = null; }
 
    setState(state) {
        console.log(`State → ${state}`);
        this.state = state;
    }
 
    getState() { return this.state; }
 
    saveToMemento() {
        return new Memento(this.state); // 拍一張快照
    }
 
    restoreFromMemento(memento) {
        this.state = memento.getState();
        console.log(`State 回復到 → ${this.state}`);
    }
}
 
class Caretaker {
    constructor() { this.mementos = []; }
    addMemento(m) { this.mementos.push(m); }
    getMemento(index) { return this.mementos[index]; }
}
 
const editor = new Originator();
const history = new Caretaker();
 
editor.setState('第一版');
history.addMemento(editor.saveToMemento()); // 存檔
 
editor.setState('第二版');
history.addMemento(editor.saveToMemento()); // 存檔
 
editor.setState('改爛了');
 
// 回到第一版
editor.restoreFromMemento(history.getMemento(0));
// State 回復到 → 第一版

要注意什麼?

  • 記憶體:每個快照都佔記憶體。如果狀態很大又頻繁存檔,記憶體會爆。考慮限制快照數量或用差異存儲(只存變化的部分)
  • 深拷貝:如果狀態是物件,記得做 deep clone。不然「快照」和「現在的狀態」指向同一個 reference,改一個兩個都變

Memento vs Command

兩個都能做 undo,但方式不同:

  • Command:記錄「做了什麼操作」,undo 是「反向操作」
  • Memento:記錄「那個時間點的完整狀態」,undo 是「直接回到那個狀態」

Command 省空間(只存操作),Memento 更簡單(直接還原)。看你的場景哪個合適。


Memento Pattern 就像遊戲裡的存檔點——打 boss 之前先存一下,死了就讀檔重來。只是現實人生沒有存檔點


延伸閱讀