DEV Community

Binoy Vijayan
Binoy Vijayan

Posted on • Edited on

GoF-Momento Pattern

The Memento pattern provides a way to capture and externalise an object's internal state so that the object can be restored to this state later without violating encapsulation.

Structure:

Originator: Creates a memento containing a snapshot of its internal state and uses the memento to restore its state.

Memento: Stores the internal state of the originator object. It provides methods for retrieving the stored state but does not expose the state itself.

Caretaker: Holds the memento object but does not modify or interpret its contents. It is responsible for storing and restoring the state of the originator.

Explanation:

The Originator is the object whose state needs to be saved and restored. It creates a memento containing a snapshot of its internal state and uses the memento to restore its state later.

The Memento stores the internal state of the originator. It provides methods for the originator to retrieve the stored state but does not expose the state itself, thus preserving encapsulation.

The Caretaker is responsible for storing and restoring the state of the originator. It holds the memento object but does not modify or interpret its contents. It acts as a wrapper around the memento, allowing the originator to save and restore its state.

Example:

Consider a text editor application where the user can undo and redo changes to a document. We can use the Memento pattern to implement the undo and redo functionality:

// Originator
class TextEditor {
    private var content: String

    init(content: String) {
        self.content = content
    }

    func getContent() -> String {
        return content
    }

    func setContent(content: String) {
        self.content = content
    }

    func save() -> Memento {
        return TextMemento(content: content)
    }

    func restore(memento: Memento) {
        if let textMemento = memento as? TextMemento {
            content = textMemento.getContent()
        }
    }
}

// Memento
protocol Memento {}

class TextMemento: Memento {
    private let content: String

    init(content: String) {
        self.content = content
    }

    func getContent() -> String {
        return content
    }
}

// Caretaker
class History {
    private var states = [Memento]()

    func saveState(memento: Memento) {
        states.append(memento)
    }

    func restoreState(index: Int) -> Memento? {
        guard index >= 0 && index < states.count else {
            return nil
        }
        return states[index]
    }
}

// Example usage
let textEditor = TextEditor(content: "Initial content")
let history = History()

// Save initial state
history.saveState(memento: textEditor.save())

// Make changes
textEditor.setContent(content: "Modified content")

// Save state after modification
history.saveState(memento: textEditor.save())

// Restore to initial state
if let initialState = history.restoreState(index: 0) {
    textEditor.restore(memento: initialState)
}

print(textEditor.getContent()) // Output: Initial content

Enter fullscreen mode Exit fullscreen mode

In this example:

The TextEditor class is the originator, which holds the content of the text document.

The TextMemento class is the memento, which stores the content of the text document at a specific point in time.

The History class is the caretaker, which maintains a history of mementos and allows the text editor to save and restore its state.

We demonstrate saving the initial state, making changes, saving the modified state, and then restoring to the initial state using the mementos stored in the history.

Image description

Usage

The Memento pattern is commonly used in various software systems where the ability to save and restore an object's state is required.
Here are some common usage examples:

Undo/Redo Functionality: Text editors, graphic design software, and other applications often implement undo and redo functionality using the Memento pattern. Each action performed by the user (e.g., typing text, moving objects) creates a memento capturing the state before the action. Users can then undo or redo actions by restoring the state from the corresponding memento.

Version Control Systems: Version control systems like Git or SVN use the Memento pattern to store and manage different versions of files or code repositories. Each commit represents a snapshot of the repository's state, allowing users to revert to previous versions if needed.

Transactional Systems: In transactional systems, such as banking or e-commerce applications, the Memento pattern can be used to implement rollback functionality. Before executing a transaction (e.g., transferring funds, placing an order), the system creates a memento representing the current state. If the transaction fails or needs to be rolled back, the system restores the state from the memento.

Game State Management: Video games often use the Memento pattern to manage game state and allow players to save and load their progress. Each save file contains a memento representing the player's position, inventory, and other relevant game state information.

Configuration Management: Configuration management tools, such as Ansible or Puppet, can use the Memento pattern to capture and restore configurations for servers or virtual machines. Administrators can save snapshots of the system's configuration and apply them later to restore the system to a known state.

Session Management: Web applications can use the Memento pattern to manage user sessions and maintain state between requests. Session data, such as user preferences or shopping cart contents, can be stored in mementos and restored when the user revisits the site.

Text Editor and IDE State: Text editors and integrated development environments (IDEs) often use the Memento pattern to implement features like session recovery. In the event of a crash or unexpected shutdown, the editor can restore the user's work from a previously saved state.

Overall, the Memento pattern is valuable in scenarios where objects need to be able to save and restore their state, providing users with flexibility, reliability, and control over their interactions with the system.

Overview of GoF Design Patterns

Top comments (0)