JavaのMementoデザインパターン

1. 概要

このチュートリアルでは、Memento Design Patternの概要と使用方法を学習します。
最初に、少し理論を説明します。 次に、パターンの使用法を説明する例を作成します。

2. Memento Design Patternとは何ですか?

https://www.oreilly.com/library/view/design-patterns-elements/0201633612/[Gang of Fourの本]で説明されているMementoデザインパターンは、動作デザインパターンです。 * Memento Design Patternは、取り消し可能なアクションを実装するソリューションを提供します。*これは、特定の瞬間にオブジェクトの状態を保存し、実行したアクションを元に戻す必要がある場合に復元することで実現できます。
実際には、状態を保存する必要があるオブジェクトはオリジネーターと呼ばれます。 Caretakerは、状態の保存と復元をトリガーするオブジェクトであり、Mementoと呼ばれます。
Mementoオブジェクトは、できるだけ少ない情報をCaretakerに公開する必要があります。 これは、カプセル化の原則に違反するため、発信者の内部状態を外部に公開しないようにするためです。 ただし、オリジネーターは元の状態に復元するために十分な情報にアクセスする必要があります。
さまざまなオブジェクトが互いにどのように相互作用するかを示す簡単なクラス図を見てみましょう。
link:/uploads/Memento-Design-Pattern-1-100x14.png%20100w []
ご覧のとおり、オリジネーターはMementoを作成および使用できます。 一方、管理人は状態を保持してから復元します。 オリジネーターの内部表現は、外部の世界から隠されています。
ここでは、1つのフィールドを使用してオリジネーターの状態を表しますが、* 1つのフィールドに限定されず、必要な数のフィールドを使用できます*。 さらに、Mementoオブジェクトに保持されている状態は、Originatorの完全な状態と一致する必要はありません。 保持された情報がオリジネーターの状態を復元するのに十分である限り、私たちは行っても構いません。

3. Mementoデザインパターンを使用する場合

通常、Mementoデザインパターンは、一部のアクションを元に戻すことができないため、以前の状態にロールバックする必要がある状況で使用されます。 *ただし、Originatorの状態が重い場合、Memento Design Patternを使用すると、作成プロセスに費用がかかり、メモリの使用量が増加する可能性があります。*

4. Mementoパターンの例

* 4.1。 初期サンプル*

Memento Design Patternの例を見てみましょう。 テキストエディタがあるとします。
public class TextEditor {

    private TextWindow textWindow;

    public TextEditor(TextWindow textWindow) {
        this.textWindow = textWindow;
    }
}
テキストウィンドウがあり、現在入力されているテキストを保持し、さらにテキストを追加する方法を提供します。
public class TextWindow {

    private StringBuilder currentText;

    public TextWindow() {
        this.currentText = new StringBuilder();
    }

    public void addText(String text) {
        currentText.append(text);
    }
}

4.2. メメント

ここで、テキストエディターに保存および元に戻す機能を実装することを考えてみましょう。 *保存するときは、現在のテキストを保存する必要があります。 したがって、以降の変更を取り消すときに、保存したテキストが復元されます。*
そのために、Memento Design Patternを使用します。 最初に、ウィンドウの現在のテキストを保持するオブジェクトを作成します。
public class TextWindowState {

    private String text;

    public TextWindowState(String text) {
        this.text = text;
    }

    public String getText() {
        return text;
    }
}
このオブジェクトはMementoです。 ご覧のとおり、_StringBuilder_の代わりに_String_を使用して、部外者による現在のテキストの更新を防ぐことを選択します。

4.3. 創始者

*その後、_TextWindow_クラスにMementoオブジェクトを作成および使用するメソッドを提供し、_TextWindow_をOriginatorにする必要があります。*
public TextWindowState save() {
    return new TextWindowState(wholeText.toString());
}

public void restore(TextWindowState save) {
    currentText = new StringBuilder(save.getText());
}
_save()_メソッドを使用すると、オブジェクトを作成できますが、_restore()_メソッドを使用すると、オブジェクトを使用して以前の状態を復元できます。

4.4. 世話人

最後に、_TextEditor_クラスを更新する必要があります。 *管理人として、オリジネーターの状態を保持し、必要に応じて復元するよう要求します:*
private TextWindowState savedTextWindow;

public void hitSave() {
    savedTextWindow = textWindow.save();
}

public void hitUndo() {
    textWindow.restore(savedTextWindow);
}

4.5. ソリューションのテスト

サンプルの実行で動作するかどうか見てみましょう。 エディターにテキストを追加して保存し、さらに追加して、最後に元に戻すことを想像してください。 それを達成するために、現在のテキストのa__String_を返す__print()__methodを_TextEditor_に追加します。
TextEditor textEditor = new TextEditor(new TextWindow());
textEditor.write("The Memento Design Pattern\n");
textEditor.write("How to implement it in Java?\n");
textEditor.hitSave();

textEditor.write("Buy milk and eggs before coming home\n");

textEditor.hitUndo();

assertThat(textEditor.print()).isEqualTo("The Memento Design Pattern\nHow to implement it in Java?\n");
ご覧のように、最後の文は現在のテキストの一部ではありません。追加する前にMementoが保存されたためです。

5. 結論

この短い記事では、Mementoデザインパターンとその使用目的について説明しました。 また、単純なテキストエディターでの使用方法を示す例を検証しました。
この記事で使用される完全なコードは、https://github.com/eugenp/tutorials/tree/master/patterns/design-patterns-behavioral-2 [GitHub上]にあります。