Das Memento Pattern ist ein Verhaltensmuster, das es ermöglicht, den Zustand eines Objekts zu speichern und zu einem späteren Zeitpunkt wiederherzustellen, ohne die interne Struktur des Objekts offenzulegen. Es besteht aus drei Hauptkomponenten: dem Originator, dem Memento und dem Caretaker. Das Memento Pattern hilft, den Zustand eines Objekts zu sichern und es später auf diesen Zustand zurückzusetzen, ohne dabei die Kapselung zu verletzen.
Was ist das Memento Pattern?
Das Memento Pattern wird verwendet, wenn der Zustand eines Objekts gespeichert und später wiederhergestellt werden muss. Es bietet eine Möglichkeit, Objekte zu „schnappschießen“ und zu einem früheren Zustand zurückzukehren. Dabei bleibt die Implementierung des Objekts privat, und der Zustand wird über ein Memento-Objekt gespeichert.
Komponenten des Memento Patterns
- Originator: Das Objekt, dessen Zustand gespeichert werden soll. Es erstellt ein Memento und stellt es zur Verfügung.
- Memento: Das Memento speichert den Zustand des Originators. Es enthält den Zustand, der später wiederhergestellt werden kann.
- Caretaker: Der Caretaker verwaltet das Memento. Er sorgt dafür, dass das Memento gespeichert und bei Bedarf abgerufen wird, ohne den Inhalt des Mementos zu kennen.
Beispiel des Memento Patterns in C++
Im folgenden Beispiel wird das Memento Pattern verwendet, um den Zustand eines einfachen Texteditors zu speichern. Der Editor kann Änderungen am Text vornehmen, und der Zustand des Textes kann zu einem späteren Zeitpunkt wiederhergestellt werden.
#include <iostream>
#include <string>
#include <memory>
#include <vector>
// Memento: Das Memento speichert den Zustand des Originators
class Memento {
private:
std::string state;
public:
Memento(const std::string& state) : state(state) {}
std::string getState() const {
return state;
}
};
// Originator: Das Objekt, dessen Zustand gespeichert wird
class Originator {
private:
std::string state;
public:
void setState(const std::string& state) {
this->state = state;
}
std::string getState() const {
return state;
}
std::shared_ptr<Memento> createMemento() {
return std::make_shared<Memento>(state);
}
void restoreMemento(const std::shared_ptr<Memento>& memento) {
state = memento->getState();
}
};
// Caretaker: Verwalter des Memento
class Caretaker {
private:
std::vector<std::shared_ptr<Memento>> mementos;
public:
void addMemento(const std::shared_ptr<Memento>& memento) {
mementos.push_back(memento);
}
std::shared_ptr<Memento> getMemento(int index) {
return mementos[index];
}
};
// Client-Code
int main() {
// Originator und Caretaker initialisieren
Originator editor;
Caretaker caretaker;
// Ursprünglichen Zustand setzen
editor.setState("Version 1: Hallo Welt");
caretaker.addMemento(editor.createMemento());
// Zustand ändern
editor.setState("Version 2: Hallo C++");
caretaker.addMemento(editor.createMemento());
// Zustand wiederherstellen
editor.restoreMemento(caretaker.getMemento(0));
// Ausgabe des wiederhergestellten Zustands
std::cout << "Wiederhergestellter Zustand: " << editor.getState() << std::endl;
return 0;
}
Erklärung des C++-Beispiels
- Memento: Das
Memento
speichert den Zustand desOriginator
in einer privaten Variablen (state
). Es stellt eine MethodegetState()
zur Verfügung, um den gespeicherten Zustand abzurufen. - Originator: Der
Originator
hat einstate
-Attribut, das den Zustand des Texteditors repräsentiert. Die MethodecreateMemento()
erstellt ein Memento, das den aktuellen Zustand speichert. Die MethoderestoreMemento()
stellt den gespeicherten Zustand aus einem Memento wieder her. - Caretaker: Der
Caretaker
verwaltet eine Liste von Mementos. Er fügt Mementos hinzu und kann bei Bedarf ein Memento aus der Liste abrufen. Der Caretaker kennt jedoch nicht den Inhalt des Mementos. - Client: Der Client erstellt den
Originator
und denCaretaker
. Er setzt den Zustand desOriginators
, speichert diesen Zustand in einem Memento und kann später zu einem gespeicherten Zustand zurückkehren.
Vorteile des Memento Patterns
- Kapselung: Der Zustand eines Objekts kann gespeichert und wiederhergestellt werden, ohne dass andere Objekte Zugriff auf die interne Struktur des Objekts benötigen.
- Flexibilität: Das Memento Pattern ermöglicht es, den Zustand zu einem beliebigen Zeitpunkt zu speichern und später darauf zuzugreifen.
- Sicherheit: Der Caretaker hat keinen Zugriff auf die Details des Mementos. Dies sorgt dafür, dass der Zustand sicher und unveränderlich bleibt.
- Vermeidung von Änderungen: Änderungen am Zustand eines Objekts können rückgängig gemacht werden, ohne dass die Logik des Objekts oder des Clients verändert werden muss.
Nachteile des Memento Patterns
- Speicherverbrauch: Wenn häufig Mementos erstellt und gespeichert werden, kann der Speicherverbrauch steigen. Jedes Memento benötigt Speicherplatz für den Zustand.
- Komplexität: Das Memento Pattern kann zusätzliche Komplexität einführen, insbesondere wenn viele verschiedene Zustände gespeichert werden müssen.
- Verwaltung der Mementos: Der Caretaker muss die Mementos verwalten, was in großen Systemen unübersichtlich werden kann. Es erfordert eine klare Struktur und Organisation.
Fazit
Das Memento Pattern ist besonders nützlich, wenn der Zustand eines Objekts über längere Zeit gespeichert und später wiederhergestellt werden muss. Es schützt die Kapselung des Objekts, indem der Zustand in einem Memento-Objekt gespeichert wird. Das Beispiel in C++ zeigt, wie das Muster einfach implementiert werden kann und wie es eine flexible Möglichkeit bietet, den Zustand von Objekten zu verwalten. Das Memento Pattern eignet sich hervorragend in Situationen, in denen Objekte oft in verschiedene Zustände wechseln und diese Zustände später wiederhergestellt werden müssen.
Zurück zur Pattern-Liste: Liste der Design-Pattern