Memento Design pattern in Rust

Memento pattern is used to restore the state of an object to a previous state. As your application is progressing, you may want to save checkpoints in your application and restore back to those checkpoints later.

The purpose of the memento design pattern is to provide the ability to execute an undo action in order to restore an object to a previous state. The Memento pattern is also known as Token.

For example, when you use a text editor such as vim or emacs, do you use undo? Why do you think this undo command can perform? As one way, all statuses(sometimes not all) are recorded as a type of object. Then you can recover this object to use this recovered data in your application.

Undo or backspace or ctrl+z is one of the most used operation in an editor. A memento design pattern is used to implement the undo operation. This is done by saving the current state of the object as it changes state.

One important point to not in implementing memento design pattern is, the encapsulation of the object should not be compromised.

Memento Pattern participants

  • originator : the object for which the state is to be saved. It creates the memento and uses it in future to undo.
  • memento : the object that is going to maintain the state of originator. Its just a POJO.
  • caretaker : the object that keeps track of multiple memento. Like maintaining savepoints.

The originator will store the state information in the memento object and retrieve old state information when it needs to back track. The memento just stores what the originator gives to it. Memento object is unreachable for other objects in the application.

// Memento pattern

// Originator has its state.

// Caretaker memorize Originator's previous states.

// Every Originator's state has Memento trait.

pub fn memento() { let mut caretaker = ConcreteCaretaker::new(); let mut originator = ConcreteOriginator(10);
caretaker.add_memento(originator.generate_memento()); println!("{:?}", originator); originator.0 = 99; println!("{:?}", originator); originator.restore_from_memento(caretaker.get_memento(0)); println!("{:?}", originator); }

trait Originator { fn generate_memento(&self) -> Box<Memento>; fn restore_from_memento(&mut self, &Memento); }

trait Caretaker { fn add_memento(&mut self, Box<Memento>); fn get_memento(&mut self, usize) -> &Memento; }

trait Memento { fn get_value(&self) -> usize; }

struct ConcreteOriginator(usize);
impl Originator for ConcreteOriginator { fn generate_memento(&self) -> Box<Memento> { Box::new(ConcreteMemento(self.0)) }
fn restore_from_memento(&mut self, m: &Memento) { self.0 = m.get_value() } }

struct ConcreteMemento(usize);
impl Memento for ConcreteMemento { fn get_value(&self) -> usize { self.0 } }

struct ConcreteCaretaker { history: Vec<Box<Memento>>, }

impl ConcreteCaretaker { fn new() -> ConcreteCaretaker { ConcreteCaretaker { history: Vec::new(), } } }

impl Caretaker for ConcreteCaretaker { fn add_memento(&mut self, m: Box<Memento>) { self.history.push(m) }
fn get_memento(&mut self, index: usize) -> &Memento { &*self.history[index] } }

Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions