ちゃんなるぶろぐ

エンジニア5年生🧑‍💻 オライリーとにらめっこする毎日。

【5分でわかる🏆】TypeScriptでDesign Pattern〜Memento Pattern〜

どうも、ちゃんなるです!

今回は、Memento Patternを紹介します🖐️

概要

Memento Patternは、オブジェクトの状態を保存し、後で復元できるようにするデザインパターンです。

これにより、オブジェクトが以前の状態に戻ることができます。

このパターンは、特にアプリケーションでアンドゥやリドゥ機能が必要な場合に有用です。

今回示すプログラムの設計

エディタアプリケーションを例に、Memento Patternを使ってアンドゥ/リドゥ機能を実装してみましょう。

クラス図

サンプルコードのクラス図:Mermaid Live Editorで作成

クラス名 役割
Editor 状態を持つオブジェクト。Mementoを作成し、状態を復元できるメソッドを提供します。
EditorMemento エディタの状態を保持するオブジェクト。エディタの状態を保持し、後で復元できるようにします。
EditorCaretaker Mementoの保存と復元を管理するオブジェクト。アンドゥ/リドゥ機能を実現します。

サンプルコード

class Editor {
  private content: string;

  constructor(content: string) {
    this.content = content;
  }

  getContent(): string {
    return this.content;
  }

  setContent(content: string): void {
    this.content = content;
  }

  createMemento(): EditorMemento {
    return new EditorMemento(this.content);
  }

  restore(memento: EditorMemento): void {
    this.content = memento.getContent();
  }
}
class EditorMemento {
  private readonly content: string;

  constructor(content: string) {
    this.content = content;
  }

  getContent(): string {
    return this.content;
  }
}
class EditorCaretaker {
  private mementos: EditorMemento[] = [];
  private current: number = -1;

  save(editor: Editor): void {
    const memento = editor.createMemento();
    this.mementos = this.mementos.slice(0, this.current + 1);
    this.mementos.push(memento);
    this.current++;
  }

  undo(editor: Editor): void {
    if (this.current <= 0) return;
    this.current--;
    editor.restore(this.mementos[this.current]);
  }

  redo(editor: Editor): void {
    if (this.current >= this.mementos.length - 1) return;
    this.current++;
    editor.restore(this.mementos[this.current]);
  }
}

では、実際に使ってみましょう🖐️

const editor = new Editor("Hello, world!");
const caretaker = new EditorCaretaker();

console.log(`Initial content: ${editor.getContent()}`);
caretaker.save(editor);

editor.setContent("Hello, Memento Pattern!");
console.log(`Updated content: ${editor.getContent()}`);
caretaker.save(editor);

editor.setContent("Hello, readers!");
console.log(`Updated content: ${editor.getContent()}`);
// Don't save "Hello, readers!".

caretaker.undo(editor);
console.log(`Content after undo: ${editor.getContent()}`);

caretaker.redo(editor);
console.log(`Content after redo: ${editor.getContent()}`);

このコードは、エディタの状態を変更しながら、アンドゥとリドゥ機能を利用して状態を復元しています。

最初の状態でエディタを作成し、その後コンテンツを更新してMementoを保存します。

アンドゥ操作で以前の状態に戻り、リドゥ操作で再び更新された状態に戻ります。

Memento Patternの使い道

  • アンドゥやリドゥ機能が必要なアプリケーションで、オブジェクトの状態を保存し、復元できるようにする場合
  • オブジェクトの状態変更が一時的であり、後で以前の状態に戻すことが必要な場合

組み合わせられるデザインパターン

  • Command Pattern: Memento Patternと組み合わせて、アクションと状態の両方を保存・復元できるようにすることができます。

※執筆中

  • State Pattern: Memento Patternと組み合わせて、オブジェクトの状態遷移を管理し、過去の状態に戻すことができます。

chan-naru.hatenablog.com

まとめ

Memento Patternは、オブジェクトの状態を保存し、後で復元できるようにするデザインパターンです。

今回の記事では、具体的なシナリオとしてエディタアプリケーションのアンドゥ/リドゥ機能を例に挙げ、TypeScriptでの実装例を提供しました。

Memento Patternは多くのシナリオで有用であり、他のデザインパターンと組み合わせることで、より強力なソフトウェア設計が可能になります。

ぜひ、Memento Patternを活用して、状態の保存と復元を実現しましょう!

参考文献

www.oreilly.com

en.wikipedia.org