
你改了半天的文件,結果改爛了想回到一小時前的版本。沒有存檔?那就完蛋了。有存檔?那你其實就在用 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 : 保管歷史
實戰:簡易版本控制

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 之前先存一下,死了就讀檔重來。只是現實人生沒有存檔點。