Design Pattern: Memento Pattern

Summary

Pattern NameMemento Pattern
Pattern TypeBehavioral Pattern
ScopeObject
Other NamesToken
Undo
TaglineStore history of state change
Use cases1. When we want to save the state of an object
and restore that state later (like an undo feature in the app).
2. When we want to manage the internal state of an object
without violating the encapsulation of that object.
Related PatternsCommand
Iterator
Difficulty LevelMedium
Implementations

Definition

Memento pattern is responsible for maintaining the history of state change of an object. By keeping the history, Memento pattern ensures that we can check the object state history at any point, and also can revert any state change and move to the previous state.

State data of the object is not accessible from outside of the object, so data integrity of the state is ensured.

Main purpose of the Memento pattern is to store the state of object, so that it can move back and forth from the object’s history at any point in time.
On the other hand, the command pattern also enables keeping the history and enables undo, but the main purpose of the Command pattern is to wrap a command in an object, not the state history tacking.

Use Cases

Here are the use cases of Memento pattern-

  • When we want to store the object’s state history, to move forward and backward in history.
  • When we want to recover an object after an error or system crash.

Implementation

Memento pattern has 3 elements.

  1. Memento: class that we need to store the state history for.
  2. Originator: originator class is responsible for generating a new memento object, and set/unset the state of memento object.
  3. Caretaker: caretaker class is responsible for maintaining the history of the memento object. So this can be used to get the state of object in any particular situation, and also can be used to undo/revert any change done on the memento object.

Take a look at the implementation diagram.

Follow the steps below to implement Mediator pattern:

  1. Create a memento class. This class may be pre-existing.
  2. Implement function to get state of memento class.
  3. Create originator class. This class should be able to create a new Memento class object.
  4. Create caretaker class. Implement methods for setting state, getting state, and undoing (if required). In caretaker, maintain a list of memento objects whenever the state changes.
  5. In the client use originator to generate a new memento class. Perform the operation using the caretaker object.

Examples

Example #1: General Memento

Let’s take the example of a general memento.

Memento Related Classes

// Memento

class Memento

    var state: string

    constructor(stateParam: string)
        state = stateParam
    end constructor

    method getState(): string
        return state
    end method

end class


// Originator

class Originator

    var state: string

    method setState(stateParam: string)
        state = stateParam
    end method

    method getState(): string
        return state
    end method

    method setMemento(): Memento
        output "Memento Saved with timestamp => " + state

        return new Memento(state)
    end method

    method getMementoState(Memento memento)
        state = memento.getState()
    end method

end class


// Caretaker

class Caretaker

    var mementoList: memento[]

    method add(Memento memento)
        mementoList.add(memento);
    end method

    method getByIndex(int index): Memento
        return mementoList.get(index);
    end method

    method getCurrent(): Memento
        return mementoList.get(mementoList.size() - 1)
    end method

    method undo()
        mementoList.remove(mementoList.size() - 1)
    end method


end class

Demo

caretaker: Caretaker = new Caretaker()
originator: Originator = new Originator()

originator.setState("Time - 1 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())

originator.setState("Time - 2 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())

originator.setState("Time - 3 : " + System.currentTimeMillis())
caretaker.add(originator.setMemento())



output "Check state at index 1 (index starts at 0):"

stateAtIndex1: Memento = caretaker.getByIndex(1)

output stateAtIndex1.getState()



output "Check last state:"

lastState: Memento = caretaker.getCurrent()

output lastState.getState()



output "Undoing last state"

caretaker.undo()



output "Check last state after undo:"

lastStateAfterUndo: Memento = caretaker.getCurrent()

output lastStateAfterUndo.getState()

Output

Memento Saved with timestamp => Time - 1 : 1677470491085
Memento Saved with timestamp => Time - 2 : 1677470492106
Memento Saved with timestamp => Time - 3 : 1677470493113



Check state at index 1 (index starts at 0):
Time - 2 : 1677470492106



Check last state:
Time - 3 : 1677470493113


Undoing last state



Check last state after undo:
Time - 2 : 1677470492106

Code Implementations

Use the following links to check Memento pattern implementation in specific programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.