Memento (Entwurfsmuster)

Ein Memento (englisch memento pattern, auch Token) ist in der Softwareentwicklung ein Entwurfsmuster, das zur Kategorie der Verhaltensmuster (englisch behavioral patterns) gehört. Das Muster dient der Erfassung und Externalisierung des internen Zustands eines Objektes, wobei sichergestellt wird, dass dadurch seine Kapselung nicht verletzt wird. So kann das Objekt zu einem späteren Zeitpunkt wieder in diesen Zustand zurückversetzt werden.[1] Es ist eines der sogenannten GoF-Muster.

Verwendung

Das Memento findet Anwendung, wenn

  • eine Momentaufnahme des (Teil-)Zustands eines Objektes zwischengespeichert werden muss
  • verhindert werden soll, dass eine direkte Schnittstelle zur Ermittlung des Zustands Implementierungsdetails offenlegt

Ein typischer Anwendungsfall ist beispielsweise die Implementierung von Haltepunkten oder Undo-Mechanismen.

Akteure

Das Memento-Muster hat die Akteure Originator und Memento. Der Originator ist ein Objekt mit einem internen Zustand, der verändert werden kann. Im Memento kann dieser Zustand abgespeichert werden, um zu einem späteren Zeitpunkt wiederhergestellt zu werden.

Vorteile

  • Datenkapselung kann aufrechterhalten werden, womit keine direkte Sichtbarkeit beziehungsweise Zugriffsmöglichkeit auf Attribute eines Objekts entsteht
  • Das Muster stellt eine einfache Möglichkeit dar, eine teilweise Schnittstelle zu schaffen

Beispiel

Folgendes Javaprogramm stellt den Rückgängig-Mechanismus (undo) in Java dar.

public class MementoDemo {

  public static void main(String[] args) {
    Originator originator = new Originator();

    originator.set("State1");
    originator.set("State2");
    Memento memento1 = originator.saveToMemento();
    originator.set("State3");
    // We can request multiple mementos, and choose which one to roll back to.
    Memento memento2 = originator.saveToMemento();
    originator.set("State4");

    originator.restoreFromMemento(memento2);
  }
}

public class Memento {
  /** State of the memento */
  private final String state;

  public Memento(final String stateToSave) {
    state = stateToSave;
  }

  public String getSavedState() {
    return state;
  }
}

public class Originator {

  /** Current state */
  private String state;

  // The class could also contain additional data that is not part of the
  // state saved in the memento.

  public void set(String state) {
    System.out.println("Originator: Setting state to " + state);
    this.state = state;
  }

  public Memento saveToMemento() {
    System.out.println("Originator: Saving to Memento.");
    return new Memento(state);
  }

  public void restoreFromMemento(Memento memento) {
    state = memento.getSavedState();
    System.out.println("Originator: State after restoring from Memento: " + state);
  }

}

Die Ausgabe lautet:

Originator: Setting state to State1
Originator: Setting state to State2
Originator: Saving to Memento.
Originator: Setting state to State3
Originator: Saving to Memento.
Originator: Setting state to State4
Originator: State after restoring from Memento: State3

In diesem Beispiel wird ein String als Zustand verwendet, der in Java standardmäßig unveränderbar ist. Üblicherweise ist der Zustand aber ein normales Objekt, das man klonen muss, bevor man es im Memento verwendet:

private Memento(final State state)
{
    // Der Zustand muss zuerst geklont werden, bevor
    // das Memento zurückgegeben wird, oder aufeinanderfolgende
    // Aufrufe würden auf ein und dasselbe Objekt zugreifen.
    mementoState = state.clone();
}

Die oben angegebene Implementierung hat einen Nachteil, indem sie eine interne Klasse deklariert. Es wäre besser, wenn die Memento-Strategie auf mehr als ein Objekt anwendbar wäre.

Grundsätzlich gibt es drei andere Wege, ein Memento zu realisieren:

  1. Die Serialisierung.
  2. Eine Klasse im selben Paket zu deklarieren.
  3. Auf das Objekt über einen Stellvertreter zugreifen, der die Sicherungs- und Wiederherstellungsoperation durchführt.
Commons: Memento – Sammlung von Bildern, Videos und Audiodateien
Wikibooks: Memento-Implementierungen in anderen Programmiersprachen – Lern- und Lehrmaterialien
  • H. Van de Sompel, M. Nelson, R. Sanderson: RFC 7089 – HTTP Framework for Time-Based Access to Resource States -- Memento. Dezember 2013 (Mementos für die Web-Archivierung, englisch).

Einzelnachweise

  1. Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides: Entwurfsmuster. 5. Auflage. Addison-Wesley, 1996, ISBN 3-8273-1862-9, S. 354. 
VD
Entwurfsmuster
Erzeugungsmuster

Abstrakte Fabrik | Erbauer | Fabrikmethode | Prototyp | Singleton | Multiton | Objektpool

Strukturmuster

Adapter | Brücke | Decorator | Fassade | Fliegengewicht | Kompositum | Stellvertreter

Verhaltensmuster

Beobachter | Besucher | Interpreter | Iterator | Kommando | Memento | Schablonenmethode | Strategie | Vermittler | Zustand | Zuständigkeitskette | Interceptor | Nullobjekt | Protokollstapel

Muster für objektrelationale Abbildung

Datentransferobjekt | Table Data Gateway | Row Data Gateway | Active Record | Unit of Work | Identity Map | Lazy Loading | Identity Field | Dependent Mapping | Embedded Value | Serialized LOB | Inheritance Mapper | Metadata Mapping | Query Object | Command-Query-Responsibility-Segregation

Nachrichtenübermittlungsmuster

Message | Command Message | Document Message | Event Message | Request-Reply | Return Address | Correlation Identifier | Message Sequence | Message Expiration | Format Indicator | Message Channel | Point-to-Point Channel | Publisher-Subscriber Channel | Datatype Channel | Invalid Message Channel | Dead Letter Channel | Guaranteed Delivery | Channel Adapter | Messaging Bridge | Message Bus | Pipes-and-Filters | Message Router | Content-based Router | Message Filter | Dynamic Router | Recipient List | Splitter | Aggregator | Resequencer | Composed Message Processor | Scatter-Gather | Routing Slip | Process Manager | Message Broker | Message Translator | Envelope Wrapper | Content Enricher | Content Filter | Claim Check | Normalizer | Canonical Data Model | Message Endpoint | Messaging Gateway | Messaging Mapper | Transactional Client | Polling Consumer | Event-driven Consumer | Competing Consumers | Message Dispatcher | Selective Consumer | Durable Subscriber | Idempotent Receiver | Service Activator | Control Bus | Detour | Wire Tap | Message History | Message Store | Smart Proxy | Test Message | Channel Purger

Andere

Application Controller | Business Delegate | Data Access Object | Dependency Injection | Extension Interface | Fluent Interface | Inversion of Control (IoC) | Lock | Model View Controller (MVC) | Model View Presenter (MVP) | Model View Update (MVU) | Model View ViewModel (MVVM) | Page Controller | Registry | Remote Facade | Repository | Service Locator | Session State | Table Module | Template View | Threadpool | Transaction Script | Transform View | Two-Step View | Value Object