Design patterns: Memento
24th May 2022
Ever make a bad decision in a game and load up a save ? Or fill in one of those forms that has 12 steps but if you muck up you can go back a few steps and everything previously filled in is still there ? Chances are you've encountered the memento pattern.
It is essentially an "Undo" button. It allows you to load a previous example of state. It consists of 3 main actors: the originator, the memento and the caretaker.
This can (probably) be found here
The originator
The originator is essentially our state object. It can create a snapshot or memento of its own state and can restore its state when given a memento. In our example, that will be a class which represents a Textview.
public class MementoTextView {
private String text;
public MementoTextView(String text) {
this.text = text;
}
public Memento takeSnapshot() {
return new Memento(this.text);
}
public void restore(Memento memento) {
this.text = memento.text;
}
public static class Memento {
...
}
}
The takeSnapshot
method allows us to create a snapshot of the state. The restore
method can be used to restore state from a previous snapshot.
The memento
This represents a snapshot of your state. Therefore the fields described in this will often be a mirror of what is in your originator. You don't want to expose anything in this to your caretaker. That is why I have made it within my originator class.
public static class Memento {
private final String text;
private Memento(String text) {
this.text = text;
}
}
The caretaker
The caretaker is responsible of creating snapshots and storing them to be used to restore state if needed. In this example I am using the Activity of an Android application as the caretaker.
It contains a list of the mementos and when a button is pressed it will use the memento to restore a TextView to an earlier state.
class MementoActivity : AppCompatActivity() {
private val mementos = mutableListOf<MementoTextView.Memento>()
private fun saveMemento() {
et_memento?.let {
val mementoTextView = MementoTextView(it.text.toString())
mementos.add(mementoTextView.takeSnapshot())
currentTextView = mementoTextView
}
}
private fun undoChanges() {
et_memento?.apply {
val lastSave = mementos.last()
currentTextView?.restore(lastSave)
setText(currentTextView?.text)
mementos.remove(lastSave)
}
}
}
Again, this can (probably) be found here