- Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
- The intent of the Memento pattern is to provide storage as well as restoration of an object.
- The mechanism in which you store the object’s state depends on the required duration of persistence which could be a few seconds, a few days, or possibly years.
- Storage options include memory (for example Session), a scratch file, or a database.
- In an abstract sense you can view a database as an implementation of the Memento design pattern. However, the most common reason for using this pattern is to capture a snapshot of an object’s state so that any subsequent changes can be undone easily if necessary.
- In .NET the most common implementation is when serializing and de-serializing objects to save and restore an object’s state.
- Essentially, a Memento is a small repository that stores an object’s state.
- Scenarios in which you may want to restore an object into a state that existed previously include: saving and restoring the state of a player in a computer game or the implementation of an undo operation in a database.
- The Memento pattern creates a snapshot of an object’s state and then offers the ability to restore it to its original state.
- This is what the serialization architecture of .NET offers and therefore qualifies as an example of Memento in the .NET Framework.
Participants
Memento
(Memento)
- Stores internal state of the
Originator
object.
- The memento may store as much or as little of the originators internal state as necessary.
- Protect against access by objects of other than the originator.
- Mementos have effectively two interfaces.
- Caretaker sees a narrow interface to the Memento — it can only pass the memento to the other objects.
- Originator, in contrast, sees a wide interface, one that lets it access all the data necessary to restore itself to its previous state.
- Ideally, only the originator that produces the memento would be permitted to its internal state.
Originator
(SalesProspect)
- Creates a memento containing a snapshot of its current internal state.
- Uses the memento to restore its internal state.
Caretaker
(MementoHolder)
- Is responsible for the memento's safekeeping.
- Never operates on or examines the contents of a memento.
var salesProspect = new SalesProspect
{
Name = "Noel van Halen",
Phone = "(412) 256-0990",
Budget = 25000.0
};
var salesProspectMemento = salesProspect.Copy();
var prospectMemory = new MementoHolder(salesProspectMemento);
salesProspect.Name = "Leo Welch";
salesProspect.Phone = "(310) 209-7111";
salesProspect.Budget = 1000000.0;
salesProspect.Restore(prospectMemory.Memento);
public class SalesProspect
{
public string Name { get; set; }
public string Phone { get; set; }
public double Budget { get; set; }
public Memento Copy() => new Memento
{
Name = Name,
Phone = Phone,
Budget = Budget
};
public void Restore(Memento memento)
{
Name = memento.Name;
Phone = memento.Phone;
Budget = memento.Budget;
}
}
public class Memento
{
public string Name { get; set; }
public string Phone { get; set; }
public double Budget { get; set; }
}
public class MementoHolder
{
public Memento Memento { set; get; }
public MementoHolder(Memento memento) => Memento = memento;
}
Rules of Thumb
- Command and Memento act as magic tokens to be passed around and invoked at a later time.
- In Command, the token represents a request; in Memento, it represents the internal state of an object at a particular time.
- Polymorphism is important to Command, but not to Memento because its interface is so narrow that a memento can only be passed as a value.
- Command can use Memento to maintain the state required for an undo operation.
- Memento is often used in conjunction with Iterator.
- An Iterator can use a Memento to capture the state of an iteration.
- The Iterator stores the Memento internally.