Memento design pattern provides the ability to store and restore object’s internal state without breaking encapsulation. This pattern is useful when we have to support undo or redo operations over an object.
In OOPS, every object has internal state. To support undo/redo operations, we must save the state to somewhere. But due to encapsulation, object private/protected properties and methods are not available so that other objects can save these to external object.
Memento provides a memento object to save internal state of an object. This memento object can be restore later.
Structure
Participants
Memento: It stores internal state of the Originator object.
Originator: Responsible for creating and restoring memento object.
Caretaker: It is responsible for saving the memento object. Caretaker cannot modify the memento object.
Example
Calculator has an internal variable result. Calculator encapsulate the result variable and don’t want any other client to change the result variable. Calculator has CreateMemento and SetMemento methods. CreateMemento returns a new CalculatorMemento object encapsulate the Calculator internal state. SetMemento method takes parameter of CalculatorMemento object and restore the Calculator to its original state.
Below is the implementation of above diagram in C#.
class Program
{
static void Main(string[] args)
{
Calculator calc = new Calculator();
calc.Add(4); // result 4
calc.Add(3); // result 7
calc.Subtract(1); // result 6
CalculatorMemento checkPoint1 = calc.CreateMemento();
calc.Add(1); // result 7
calc.Print(); // print 7
calc.SetMemento(checkPoint1);
calc.Print(); // result 6
}
}
public class Calculator
{
private int result = 0;
public int Add(int a)
{
this.result += a;
return this.result;
}
public int Subtract(int a)
{
this.result -= a;
return this.result;
}
public void Print()
{
Console.WriteLine("Result: " + this.result);
}
public CalculatorMemento CreateMemento()
{
CalculatorMemento calcMemento = new CalculatorMemento();
calcMemento.SetState(this.result);
return calcMemento;
}
public void SetMemento(CalculatorMemento memento)
{
this.result = memento.GetState();
}
}
public class CalculatorMemento
{
private int state;
public int GetState()
{
return this.state;
}
public void SetState(int state)
{
this.state = state;
}
}