Memento Design Pattern in Kotlin

1. Definition

The Memento Design Pattern provides a way to capture an object's internal state such that it can be restored to this state later. This is especially useful when you need to implement features like undo and redo.

2. Problem Statement

Often, there are cases where we want to give the user the ability to undo their actions or maintain a history of object states for some reason. However, directly exposing the object's internals for backup might violate encapsulation.

3. Solution

Use a memento object to hold a snapshot of the original object's state. The original object, known as the originator, provides a mechanism to save and restore its state from the memento, ensuring that the internal details are not exposed.

4. Real-World Use Cases

1. Saving and restoring game progress in video games.

2. Implementing the undo and redo functionality in software like graphic editors.

3. Capturing system snapshots for rollback capabilities.

5. Implementation Steps

1. Create the Memento class to store the internal state of the Originator.

2. The Originator class should have methods to save its state to a memento and restore its state from a memento.

3. Implement a Caretaker class that maintains a list of mementos for the purpose of undo and redo.

6. Implementation in Kotlin Programming

// Step 1: Memento class
data class Memento(val state: String)
// Step 2: Originator class
class Originator(var state: String) {
    fun createMemento(): Memento {
        return Memento(state)
    }
    fun restore(memento: Memento) {
        state = memento.state
    }
}
// Step 3: Caretaker class
class Caretaker {
    private val mementoList = mutableListOf<Memento>()
    fun saveState(originator: Originator) {
        mementoList.add(originator.createMemento())
    }
    fun undo(originator: Originator) {
        if (mementoList.isNotEmpty()) {
            val memento = mementoList.removeAt(mementoList.size - 1)
            originator.restore(memento)
        }
    }
    // More methods like redo can be added similarly
}
// Client Code
fun main() {
    val originator = Originator("Initial State")
    val caretaker = Caretaker()
    caretaker.saveState(originator)
    originator.state = "State #1"
    caretaker.saveState(originator)
    originator.state = "State #2"
    println("Current State: ${originator.state}")
    caretaker.undo(originator)
    println("After undo: ${originator.state}")
}

Output:

Current State: State #2
After undo: State #1

Explanation:

1. The Memento captures the internal state of the Originator without violating its encapsulation.

2. The Originator can save and restore its state using the memento.

3. The Caretaker provides a mechanism to keep track of multiple mementos, allowing for functionalities like undo and redo.

7. When to use?

The Memento pattern is useful when:

1. You need to capture and externalize an object's internal state without exposing its details.

2. You want to provide a mechanism for restoring an object to its previous states (e.g., undo/redo).

3. The direct interface to obtain the state would expose implementation details and break the object's encapsulation.

Comments