Memento Pattern

Memento Pattern

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

  1. Originator: Das Objekt, dessen Zustand gespeichert werden soll. Es erstellt ein Memento und stellt es zur Verfügung.
  2. Memento: Das Memento speichert den Zustand des Originators. Es enthält den Zustand, der später wiederhergestellt werden kann.
  3. 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

  1. Memento: Das Memento speichert den Zustand des Originator in einer privaten Variablen (state). Es stellt eine Methode getState() zur Verfügung, um den gespeicherten Zustand abzurufen.
  2. Originator: Der Originator hat ein state-Attribut, das den Zustand des Texteditors repräsentiert. Die Methode createMemento() erstellt ein Memento, das den aktuellen Zustand speichert. Die Methode restoreMemento() stellt den gespeicherten Zustand aus einem Memento wieder her.
  3. 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.
  4. Client: Der Client erstellt den Originator und den Caretaker. Er setzt den Zustand des Originators, speichert diesen Zustand in einem Memento und kann später zu einem gespeicherten Zustand zurückkehren.

Vorteile des Memento Patterns

  1. Kapselung: Der Zustand eines Objekts kann gespeichert und wiederhergestellt werden, ohne dass andere Objekte Zugriff auf die interne Struktur des Objekts benötigen.
  2. Flexibilität: Das Memento Pattern ermöglicht es, den Zustand zu einem beliebigen Zeitpunkt zu speichern und später darauf zuzugreifen.
  3. Sicherheit: Der Caretaker hat keinen Zugriff auf die Details des Mementos. Dies sorgt dafür, dass der Zustand sicher und unveränderlich bleibt.
  4. 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

  1. Speicherverbrauch: Wenn häufig Mementos erstellt und gespeichert werden, kann der Speicherverbrauch steigen. Jedes Memento benötigt Speicherplatz für den Zustand.
  2. Komplexität: Das Memento Pattern kann zusätzliche Komplexität einführen, insbesondere wenn viele verschiedene Zustände gespeichert werden müssen.
  3. 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

VG WORT Pixel