Skip to content

MementoPattern

MidasXIV edited this page Apr 27, 2024 · 3 revisions

Memento Pattern

The Memento design pattern is used to capture the internal state of an object and externalize it so that it can be restored later. It is useful when you need to save the state of an object and restore it later, without exposing the internal state of the object.

You should think of the Memento pattern when you need to:

  • Save the state of an object and restore it later
  • Implement undo/redo functionality
  • Implement a "save" and "load" functionality for an object
  • Implement a "snapshot" functionality for an object

The easiest way to understand the intent of the Memento pattern is to look at examples of where it is useful.

The Memento pattern is useful in applications that require saving and restoring the state of an object, such as:

  • Text editors that allow users to undo and redo changes
  • Games that allow players to save and load their progress
  • Chat applications that allow users to save and restore their chat history

Steps to implementing the Memento pattern in TypeScript:

Let's consider a scenario where we're building a "Digital Art Gallery" Museum; We wish to always have a snapshot of how the Museum looks, allow the curator to "undo" a proposed change or "redo" a previous action.

AGENDA : Uses the Memento pattern to save the state of each exhibit at each point in time and allow the curator to undo, redo their actions.

  1. Define the Memento interface that will hold the state of the object:
interface Memento {
  getState(): any;
}
  1. Define the Originator class: This class creates and restores mementos.

    class Exhibit {
        private state: any;
    
        setState(state: any) {
            this.state = state;
        }
    
        getState(): any {
            return this.state;
        }
    
        saveToMemento(): ExhibitMemento {
            return new ExhibitMemento(this.state);
        }
    
        restoreFromMemento(memento: ExhibitMemento) {
            this.state = memento.getState();
        }
    }
  2. Define the Memento class: This class will store the state of the exhibit.

    class ExhibitMemento {
        private state: any;
    
        constructor(state: any) {
            this.state = state;
        }
    
        getState(): any {
            return this.state;
        }
    }
  3. Define the Caretaker class: This class keeps track of mementos.

    class Caretaker {
        private mementos: ExhibitMemento[] = [];
    
        addMemento(memento: ExhibitMemento) {
            this.mementos.push(memento);
        }
    
        getMemento(index: number): ExhibitMemento {
            return this.mementos[index];
        }
    }
  4. Example usage: This demonstrates how to use the Memento pattern to save and restore the state of the exhibit.

    // Example usage
    const digitalArtGallery = new Exhibit();
    
    // Initial state
    digitalArtGallery.setState({
        exhibitName: "Monalisa",
        artist: "Leonardo da Vinci",
        year: 1503
    });
    
    const caretaker = new Caretaker();
    
    // Save initial state
    caretaker.addMemento(digitalArtGallery.saveToMemento());
    
    // Make some changes
    digitalArtGallery.setState({
        exhibitName: "Starry Night",
        artist: "Vincent van Gogh",
        year: 1889
    });
    
    // Save new state
    caretaker.addMemento(digitalArtGallery.saveToMemento());
    
    // Restore to previous state
    digitalArtGallery.restoreFromMemento(caretaker.getMemento(0));
    
    console.log(digitalArtGallery.getState()); // Output: { exhibitName: "Monalisa", artist: "Leonardo da Vinci", year: 1503 }

How it works:

  1. The Originator class uses the Memento pattern to save and restore its state.
  2. The Memento interface defines the getState() method that returns the state of the object.
  3. The ConcreteMemento class implements the Memento interface and holds the state of the object.
  4. The Originator class uses the ConcreteMemento class to save and restore its state.

When to use the Memento pattern over other patterns similar to it:

  • Use the Memento pattern when you need to save and restore the state of an object, and you don't care about the internal implementation details of the object.
  • Use the Observer pattern when you need to notify other objects about changes to the state of an object.
  • Use the Command pattern when you need to encapsulate a request as an object, and you don't care about the internal implementation details of the object.

Note that the Memento pattern is often used in combination with other design patterns, such as the Observer pattern, to implement undo/redo functionality.

Clone this wiki locally