Memento Design Pattern in Java

1. Übersicht

In diesem Tutorial erfahren Sie, was das Memento-Entwurfsmuster ist und wie es verwendet wird.

Zuerst werden wir ein bisschen Theorie durchgehen. Anschließend erstellen wir ein Beispiel, in dem wir die Verwendung des Musters veranschaulichen.

2. Was ist das Memento-Designmuster?

Das Memento-Entwurfsmuster, das von der Viererbande in ihrem Buch beschrieben wird, ist ein Verhaltensentwurfsmuster. Das Memento-Entwurfsmuster bietet eine Lösung zum Implementieren nicht rückgängig zu machender Aktionen. Wir können dies tun, indem wir den Status eines Objekts zu einem bestimmten Zeitpunkt speichern und wiederherstellen, wenn die seitdem ausgeführten Aktionen rückgängig gemacht werden müssen.

In der Praxis wird das Objekt, dessen Status gespeichert werden muss, als Originator bezeichnet. Der Hausmeister ist das Objekt, das das Speichern und Wiederherstellen des Zustands auslöst, der als Memento bezeichnet wird.

Das Memento-Objekt sollte dem Hausmeister so wenig Informationen wie möglich zur Verfügung stellen. Dies soll sicherstellen, dass wir den internen Zustand des Urhebers nicht der Außenwelt aussetzen, da dies die Kapselungsprinzipien verletzen würde. Der Urheber sollte jedoch auf genügend Informationen zugreifen, um den ursprünglichen Zustand wiederherzustellen.

Sehen wir uns ein kurzes Klassendiagramm an, das zeigt, wie die verschiedenen Objekte miteinander interagieren:

Wie wir sehen können, kann der Urheber ein Erinnerungsstück produzieren und konsumieren. In der Zwischenzeit behält der Hausmeister den Zustand nur vor der Wiederherstellung. Die interne Darstellung des Urhebers bleibt vor der Außenwelt verborgen.

Hier haben wir ein einzelnes Feld verwendet, um den Status des Absenders darzustellen, obwohl wir nicht auf ein Feld beschränkt sind und so viele Felder wie nötig hätten verwenden können . Außerdem muss der im Memento-Objekt enthaltene Status nicht mit dem vollständigen Status des Absenders übereinstimmen. Solange die gespeicherten Informationen ausreichen, um den Status des Absenders wiederherzustellen, können wir loslegen.

3. Wann sollte das Memento-Designmuster verwendet werden?

In der Regel wird das Memento-Entwurfsmuster in Situationen verwendet, in denen einige Aktionen nicht rückgängig gemacht werden können und daher ein Rollback auf einen vorherigen Status erforderlich ist. Wenn der Status des Absenders jedoch sehr hoch ist, kann die Verwendung des Memento-Entwurfsmusters zu einem teuren Erstellungsprozess und einer erhöhten Speichernutzung führen.

4. Beispiel für das Erinnerungsmuster

4.1. Erstexemplar

Sehen wir uns nun ein Beispiel für das Memento-Entwurfsmuster an. Stellen wir uns vor, wir haben einen Texteditor:

public class TextEditor { private TextWindow textWindow; public TextEditor(TextWindow textWindow) { this.textWindow = textWindow; } }

Es verfügt über ein Textfenster, das den aktuell eingegebenen Text enthält und eine Möglichkeit bietet, weiteren Text hinzuzufügen:

public class TextWindow { private StringBuilder currentText; public TextWindow() { this.currentText = new StringBuilder(); } public void addText(String text) { currentText.append(text); } }

4.2. Erinnerung

Stellen wir uns nun vor, wir möchten, dass unser Texteditor einige Funktionen zum Speichern und Rückgängigmachen implementiert. Beim Speichern möchten wir, dass unser aktueller Text gespeichert wird. Wenn Sie nachfolgende Änderungen rückgängig machen, wird unser gespeicherter Text wiederhergestellt.

Dazu verwenden wir das Memento Design Pattern. Zuerst erstellen wir ein Objekt, das den aktuellen Text des Fensters enthält:

public class TextWindowState { private String text; public TextWindowState(String text) { this.text = text; } public String getText() { return text; } }

Dieses Objekt ist unser Andenken. Wie wir sehen können, verwenden wir String anstelle von StringBuilder , um zu verhindern, dass der aktuelle Text von Außenstehenden aktualisiert wird.

4.3. Urheber

Danach müssen wir der TextWindow- Klasse Methoden zum Erstellen und Konsumieren des Memento-Objekts bereitstellen , wodurch das TextWindow zu unserem Urheber wird :

public TextWindowState save() { return new TextWindowState(wholeText.toString()); } public void restore(TextWindowState save) { currentText = new StringBuilder(save.getText()); }

Mit der save () -Methode können wir das Objekt erstellen, während die restore () -Methode es verwendet, um den vorherigen Status wiederherzustellen.

4.4. Hausmeister

Schließlich müssen wir unsere TextEditor- Klasse aktualisieren . Als Hausmeister behält er den Status des Urhebers bei und fordert ihn auf, ihn bei Bedarf wiederherzustellen:

private TextWindowState savedTextWindow; public void hitSave() { savedTextWindow = textWindow.save(); } public void hitUndo() { textWindow.restore(savedTextWindow); }

4.5. Testen der Lösung

Mal sehen, ob es durch einen Probelauf funktioniert. Stellen Sie sich vor, wir fügen unserem Editor Text hinzu, speichern ihn, fügen dann weiteren hinzu und machen ihn schließlich rückgängig. Um dies zu erreichen, fügen wir unserem TextEditor eine print () -Methode hinzu , die einen String des aktuellen Textes zurückgibt :

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");

Wie wir sehen können, ist der letzte Satz nicht Teil des aktuellen Textes, da das Memento vor dem Hinzufügen gespeichert wurde.

5. Schlussfolgerung

In diesem kurzen Artikel haben wir das Memento-Designmuster und seine Verwendungsmöglichkeiten erläutert. Wir haben auch ein Beispiel durchgesehen, das die Verwendung in einem einfachen Texteditor veranschaulicht.

Den vollständigen Code in diesem Artikel finden Sie auf GitHub.