Open In App

Memento Method – JavaScript Design Pattern

Last Updated : 31 Oct, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

A behavioral design pattern in JavaScript called Memento focuses on externalizing and capturing an object’s internal state so that it can later be restored. When you need to add features like undo/redo functionality, history tracking, or reverting an item to a former state, this pattern is quite helpful.

Understanding the Memento Pattern

The Memento pattern consists of three key components: the Originator, the Memento, and the Caretaker.

  • Originator: This is the object whose state needs to be saved and restored. It creates a Memento object to capture its state and can also restore its state from a Memento.
  • Memento: The Memento is an immutable object that stores the state of the Originator. It only allows the Originator to access its content, ensuring that the state remains encapsulated.
  • Caretaker: The Caretaker is responsible for keeping track of multiple Mementos. It can save and retrieve Mementos to and from an Originator.

Example

Imagine you are developing a document editor application, and you want to implement an undo/redo feature. Users should be able to revert to previous document states. Let’s apply the Memento pattern to this scenario.

Javascript




// Originator: Document
class Document {
    constructor(content) {
        this.content = content;
    }
 
    createMemento() {
        return new DocumentMemento(this.content);
    }
 
    restoreFromMemento(memento) {
        this.content = memento.getContent();
    }
 
    getContent() {
        return this.content;
    }
}
 
// Memento: DocumentMemento
class DocumentMemento {
    constructor(content) {
        this.content = content;
    }
 
    getContent() {
        return this.content;
    }
}
 
// Caretaker: HistoryManager
class HistoryManager {
    constructor() {
        this.history = [];
    }
 
    push(document) {
        this.history.push(document.createMemento());
    }
 
    pop() {
        if (this.history.length === 0) return null;
        return this.history.pop();
    }
}
 
function runDocumentEditor() {
    const editor = new Document("Initial content");
    const historyManager = new HistoryManager();
 
    historyManager.push(editor); // Save initial state
 
    editor.content = "Updated content"; // Modify the document
    historyManager.push(editor); // Save updated state
 
    editor.restoreFromMemento(historyManager.pop()); // Restore to the previous state
 
    console.log(editor.getContent()); // Output: "Initial content"
}
 
runDocumentEditor();


Output:

Updated content

In this example:

we have an Originator (Document), a Memento (DocumentMemento), and a Caretaker (HistoryManager). The HistoryManager keeps track of document states, allowing us to save and restore them.

Group-1

Diagrammatical Representation of Document Editor

Lets Break down Document Editor to get a better understanding,

1. Originator (Document):

The ‘Document’ class represents the object whose state we want to track and restore. In this case, it’s a document with content. Here’s what this class does:

  • Constructor: It initializes the ‘content’ property with the initial document content provided as a parameter.
  • createMemento(): This method creates a Memento object (an instance of ‘DocumentMemento’) that captures the current state of the document, which is the content. It returns the created Memento.
  • restoreFromMemento(memento): This method allows the document to restore its state from a given Memento. It sets the document’s content to match the content stored in the Memento.
  • getContent(): This method simply returns the current content of the document.

2. Memento (DocumentMemento):

The ‘DocumentMemento’ class represents the Memento object responsible for storing the state of the ‘Document’. Here’s what this class does:

  • Constructor: It takes the document’s content as a parameter during creation and stores it internally.
  • getContent(): This method allows external objects (in this case, the ‘Document’) to retrieve the stored content. It ensures that only the ‘Document’ can access its own content.

3. Caretaker (HistoryManager):

The ‘HistoryManager’ class acts as the caretaker, responsible for managing and keeping track of the history of document states. It uses an array to store Mementos. Here’s what this class does:

  • Constructor: Initializes an empty array called ‘history’ to store Mementos.
  • push(document): This method takes a ‘Document’ object as a parameter, creates a Memento from it using createMemento(), and then pushes the Memento onto the history array. This operation saves the current state of the document.
  • pop(): This method retrieves the most recent Memento from the ‘history’ array, effectively representing an “undo” operation. If the ‘history’ array is empty, it returns ‘null’.

4. runDocumentEditor() Function:

This function demonstrates how the Memento pattern works in practice:

  • It creates a ‘Document’ object called ‘editor’ with initial content and a ‘HistoryManager’ called ‘historyManager’ to manage the history of states.
  • It pushes the initial state of the ‘editor’ (the “Initial content”) into the ‘historyManager’.
  • It modifies the content of the ‘editor’ to “Updated content.”
  • It pushes the updated state of the ‘editor’ into the ‘historyManager’.
  • It pops the most recent state from the ‘historyManager’, effectively performing an “undo” operation.
  • Finally, it prints the content of the ‘editor’ to the console, which should show “Initial content” since we reverted to the previous state.

This example demonstrates how the Memento pattern allows you to save and restore the state of an object, making it useful for implementing features like undo/redo functionality in applications like document editors. Users can navigate through the history of changes and revert to previous states easily.

Advantages of Memento Method:

  1. State Management: The primary advantage of the Memento pattern is its ability to manage an object’s state effectively. It allows you to capture and externalize an object’s internal state without exposing its implementation details.
  2. Undo/Redo Functionality: The Memento pattern is well-suited for implementing undo and redo functionality in applications. Users can easily navigate through the history of an object’s states, providing a better user experience.
  3. Maintains Encapsulation: The pattern enforces encapsulation by ensuring that only the Originator (the object whose state is being managed) has access to the Memento’s internal state. This helps maintain the integrity of the object’s data.
  4. Flexibility: The Memento pattern is flexible and can be applied to various scenarios where you need to track and restore object states. It’s not limited to specific types of objects or use cases.
  5. Versioning: It can be used to create version control systems where you track and restore the state of objects over time. This is valuable in collaborative applications and content management systems.

Disadvantages of Memento Method:

  1. Memory Usage: Storing multiple Mementos in memory can consume a significant amount of memory, especially if you have a large number of objects with complex states. This can be a concern in resource-constrained environments.
  2. Performance Overhead: The process of creating, storing, and managing Mementos can introduce some performance overhead, particularly when dealing with large objects or frequent state changes.
  3. Complexity: Implementing the Memento pattern can introduce additional complexity to your code, especially if you need to manage the history of multiple objects or if you want to implement more advanced features like branching and merging states
  4. Potential for Data Leakage: If not implemented correctly, there’s a risk of data leakage where external objects gain access to the internal state of Mementos, violating encapsulation.
  5. behavioural: In languages without built-in support for object serialization and deep cloning, implementing Mementos and restoring object states can be more challenging and error-prone.

Conclusion:

For managing and restoring object states, the Memento design pattern is effective. It enables you to integrate functions like undo/redo capabilities into applications, enhancing user experience and data integrity. We’ve shown this pattern’s applicability in numerous real-world circumstances by utilising a distinct example. You can build more dependable and user-friendly software by mastering the Memento pattern, which can be a useful addition to your design patterns toolkit.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads