KnowHow

技術的なメモを中心にまとめます。
検索にて調べることができます。

Python基礎 オブジェクト指向20(Memento) 振る舞いに関するデザインパターン

登録日 :2026/01/28 18:35
カテゴリ :Python基礎

(オブジェクトの種類)

オブジェクトの現在の状態を保存しておき、状態が変化した場合でも、その時の状態に戻すことができるようにするパターン

  • Cntl + Zの undo機能を実現する
  • 状態を生成するクラスとその履歴を管理するクラスを分離する

構成要素

Originator

  • 保存対象となるクラス
  • 内部状態を保存するメソッドとリストアするメソッドを持つ

Memento

  • Originatorオブジェクトを保存する記憶用クラス

ConcreteMemento

  • Mementoを継承(実装)する子クラス
  • 保存した状態を取得するメソッドを持つ

Caretaker

  • Mementoオブジェクトを管理するクラス
  • バックアップやUndo のメソッドを持つ

オブジェクト指向的要素

カプセル化の破壊を防ぐパタン

  • Mementoパターンを使わず内部状態の保存・復元をする場合、状態を公開する必要がある。

  • Originator自身が保存操作を行うことで、内部状態を非公開としたままスナップショットを作成する。

メリット・デメリット

メリット

  • カプセル化の破壊することなく、オブジェクトの状態のスナップショットを作成・復元できる
  • スナップショットの管理をCaretakerに任せることで、Originatorクラスをシンプルに保ことができる

デメリット

  • Mementoを大量に作成してしまうとメモリ使用量が増加する。

使い所

スナップショットを作成したい場合

  • Undo機能
  • ゲームの保存
    など

サンプル

メモ帳のUndo機能の例

from abc import ABC, abstractmethod
import datetime
from typing import List

class Memento(ABC):
    @abstractmethod
    def get_memo(self) -> str:
        pass


class ConcreteMemento(Memento):
    def __init__(self, memo:str):
        self.__memo = memo
        self.__date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    def get_memo(self) -> str:
        return self.__memo

    def __str__(self):
        return f"{self.__date} / ({self.get_memo()})"


class Notepad(object):
    def __init__(self, memo:str):
        self.__memo = memo

    def get_memo(self) -> str:
        return self.__memo

    def add_memo(self, memo: str):
        self.__memo = memo

    def save(self) -> Memento:
        print("save memo")
        return ConcreteMemento(self.get_memo())

    def restore(self, memento: Memento):
        self.add_memo(memento.get_memo())


class Caretaker(object):

    def __init__(self, notepad: Notepad, mementos: List[Memento] = []):
        self.__notepad = notepad
        self.__mementos = mementos

    def backup(self):
        self.__mementos.append(self.__notepad.save())

    def undo(self):
        if not len(self.__mementos):
            print("There is no snapshot")
            return

        memento = self.__mementos.pop()
        self.__notepad.restore(memento)

    def show_history(self):
        for memento in self.__mementos:
            print(memento)


if __name__ == '__main__':
    notepad = Notepad("first memo")
    caretaker = Caretaker(notepad)
    caretaker.backup

    notepad.add_memo("second memo")
    caretaker.backup()

    notepad.add_memo("third memo")
    caretaker.backup()

    print(notepad.get_memo())

    caretaker.show_history()

    print("")
    caretaker.undo()
    print(notepad.get_memo())
    print("")
    caretaker.undo()
    print(notepad.get_memo())
    print("")
    caretaker.undo()
    print(notepad.get_memo())

    print(caretaker.show_history())