Memento Design Pattern in R

1. Definition

The Memento Design Pattern provides a mechanism to capture an object's internal state such that the object can be restored to this state later, without violating its encapsulation. It is primarily used to implement functionalities like undo.

2. Problem Statement

Imagine you're working with an object that undergoes multiple changes. At some point, you may need to rollback or revert the object to a previous state. Implementing such a feature without having direct access to the object's internal state can be challenging.

3. Solution

The Memento pattern proposes a solution by suggesting three primary roles:

1. Originator: The object whose state we want to save.

2. Memento: The object that stores the state of the originator.

3. Caretaker: The object that keeps track of multiple states.

By utilizing these roles, the object's state can be saved and restored without exposing its internals.

4. Real-World Use Cases

1. Undo and redo functionality in software applications.

2. Taking snapshots of system configurations.

3. Save game functionality in video games where the game's state is saved and can be loaded later.

5. Implementation Steps

1. Create the Memento class that will store the state of the Originator.

2. Implement the Originator class that creates a memento containing a snapshot of its current internal state and can also restore its state from a memento.

3. Implement the Caretaker that keeps track of multiple memento states.

6. Implementation in R Programming

# Step 1: Memento Class
Memento <- setRefClass("Memento",
  fields = list(state = "character"),
  methods = list(
    get_state = function() {
      return(state)
    }
  )
)
# Step 2: Originator Class
Originator <- setRefClass("Originator",
  fields = list(state = "character"),
  methods = list(
    create_memento = function() {
      Memento$new(state = state)
    },
    set_memento = function(memento) {
      state <<- memento$get_state()
    }
  )
)
# Step 3: Caretaker Class
Caretaker <- setRefClass("Caretaker",
  fields = list(mementos = "list"),
  methods = list(
    add_memento = function(memento) {
      mementos[[length(mementos) + 1]] <<- memento
    },
    get_memento = function(index) {
      mementos[[index]]
    }
  )
)
# Client Code
originator <- Originator$new(state = "State1")
caretaker <- Caretaker$new(mementos = list())
# Saving states
caretaker$add_memento(originator$create_memento())
originator$state <- "State2"
caretaker$add_memento(originator$create_memento())
originator$state <- "State3"
# Restoring state to State1
originator$set_memento(caretaker$get_memento(1))
cat("Restored State:", originator$state, "\n")

Output:

Restored State: State1

Explanation:

1. The Memento class stores the internal state of the Originator.

2. The Originator can create a memento (snapshot) of its current state and also restore its state from a given memento.

3. The Caretaker maintains a list of mementos. This allows us to store multiple snapshots of the Originator's state.

4. In the client code, we demonstrated how the Originator's state can be saved and restored using the Caretaker and Memento classes.

7. When to use?

The Memento Design Pattern is suitable when:

1. You need to implement a snapshot of an object's state so that it can be restored to that state later.

2. Direct exposure of an object's internals may violate its encapsulation and hence is not preferable.

3. You want to keep a history of an object's state to provide an undo mechanism.

The Memento pattern allows for detailed state preservation and restoration without compromising the principle of data encapsulation.


Comments