iT邦幫忙

2023 iThome 鐵人賽

DAY 26
0
Software Development

深入淺出設計模式 - 使用 C++系列 第 26

[Day 26] 儲存系統的重要狀態 — 備忘錄模式 (Memento Pattern)

  • 分享至 

  • xImage
  •  

Intent

  • Memento 模式是一種行為設計模式,主要用於捕獲和存儲對象的內部狀態,以便稍後可以將其恢復到這一狀態。這種模式特別有用於實現**「撤銷」操作或保存應用狀態**
    • https://ithelp.ithome.com.tw/upload/images/20231007/20138643OOSMQtDxkH.png

筆者註: 其實不只是遊戲開發的存檔功能,就連嵌入式系統中也很常使用到此 Pattern 來定期保存系統 Snapshot,以防止外部環境異常斷電 (SPOR),以便後續的系統環境 Recovery

Motivation

  • 當您需要保存對象的某個瞬間狀態,或者需要實現可撤銷操作時,Memento 模式成為一個理想的解決方案。例如,在文本編輯器、遊戲存檔或者任何需要狀態快照 (Snapshot) 的場景

Applicability

  • 撤銷操作: 用於實現可撤銷的操作,如文本編輯器的 undo 功能
  • 狀態存儲: 用於保存應用的狀態,如遊戲存檔
  • 版本控制: 用於實現對象狀態的版本控制

Structure

https://ithelp.ithome.com.tw/upload/images/20231007/20138643s0jvDxRQpr.png

Participants(參與者)

Originator (發起人): 負責創建一個 Memento,用於存儲其當前內部狀態
Memento (備忘錄): 存儲 Originator 的內部狀態,但不應對 Originator 的狀態進行任何操作
Caretaker (管理者): 負責保存和恢復 Originator 的 Memento 對象

Collaborations

  • Originator 與 Memento: Originator 使用 Memento 來保存和恢復其內部狀態
  • Caretaker 與 Memento: Caretaker 負責管理 Memento,但不應對其內部狀態進行操作

Consequences(結果)

優點

  • 狀態封裝: Memento 模式將對象的狀態封裝在 Memento 對象中,確保了對象的封裝性
  • 簡化 Originator: 由於狀態管理被委託給 Memento 和 Caretaker,Originator 類變得更簡單

缺點

  • 資源消耗: 如果需要保存大量的狀態或者頻繁地保存狀態,則可能會消耗大量的資源
  • 狀態管理複雜性: 管理多個 Memento 對象可能會變得複雜

Implementation (範例: SPOR 異常斷電恢復)

// Memento class to store system state
class SystemStateMemento {
private:
    std::string state;
public:
    SystemStateMemento(const std::string& s) : state(s) {}
    std::string getState() const { return state; }
};

// Originator class
class EmbeddedSystem {
private:
    std::string state;
public:
    void setState(const std::string& s) { state = s; }
    std::string getState() const { return state; }
    SystemStateMemento saveStateToMemento() { return SystemStateMemento(state); }
    void getStateFromMemento(const SystemStateMemento& memento) { state = memento.getState(); }
};

// Caretaker class
class Caretaker {
private:
    std::vector<SystemStateMemento> mementoList;
public:
    void add(const SystemStateMemento& state) { mementoList.push_back(state); }
    SystemStateMemento get(int index) { return mementoList[index]; }
};

int main() {
    EmbeddedSystem system;
    Caretaker caretaker;

    // Set initial state and save to memento
    system.setState("Initial State");
    caretaker.add(system.saveStateToMemento());

    // Change system state and save to memento
    system.setState("Running");
    caretaker.add(system.saveStateToMemento());

    // Simulate SPOR (Sudden Power Off Recovery)
    system.setState("Unknown");

    // Restore state from memento after SPOR
    system.getStateFromMemento(caretaker.get(1));
    std::cout << "System State after SPOR: " << system.getState() << std::endl;
}

Output:

System State after SPOR: Running

Known Uses

  • 文本編輯器: 如 Microsoft Word,用於實現 undo 和 redo 功能
  • 遊戲開發: 用於實現遊戲存檔和讀檔
  • 嵌入式系統: 掉電異常恢復

Reference

  1. https://refactoring.guru/design-patterns/memento

上一篇
[Day 25] 集中對象間複雜的控制和溝通 — 中介者模式 (Mediator Pattern)
下一篇
[Day 27] 複製複雜已知物件 - 原型模式 (Protorype Pattern)
系列文
深入淺出設計模式 - 使用 C++37
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言