Memento

Posted by Dustin Boston .


CAUTION

Construction Area
Watch out for:

  • Broken code
  • No comments
  • Partial examples
  • Missing tests

Source Code Listing

code.ts

class Memento<T> {
  constructor(private readonly state: T) {}

  getState(): T {
    return this.state;
  }
}

class Originator<T> {
  constructor(private state: T) {}

  setMemento(memento: Memento<T>): void {
    this.state = memento.getState();
  }

  createMemento(): Memento<T> {
    return new Memento<T>(this.state);
  }

  _changeState(state: T): void {
    this.state = state;
  }

  _showState(): void {
    console.log(this.state);
  }
}

class Caretaker<T> {
  private memento: Memento<T> | undefined; // Make memento optional

  constructor(private readonly originator: Originator<T>) {}

  doCommand(): void {
    this.memento = this.originator.createMemento(); // Store the memento
    // ... do something that changes the originator's state...
  }

  undoCommand(): void {
    if (this.memento) {
      // Check if a memento exists
      this.originator.setMemento(this.memento);
    } else {
      console.log("Cannot undo, no memento stored.");
    }
  }
}

const client = {
  run(): void {
    const originator = new Originator<string>("foo"); // Type the originator
    const caretaker = new Caretaker<string>(originator);

    originator._showState(); // Output: foo

    caretaker.doCommand(); // Save "foo" memento
    originator._changeState("bar");
    originator._showState(); // Output: bar

    caretaker.undoCommand();
    originator._showState(); // Output: foo

    caretaker.doCommand(); // Save "bar" memento
    originator._changeState("baz");
    originator._showState(); // Output: baz

    caretaker.undoCommand();
    originator._showState(); // Output: bar

    caretaker.undoCommand(); // Call undo again
    originator._showState(); // Output: bar (still bar, because "foo" memento is gone)
  },
};

client.run();