Memento¶
- Memento
- UML class diagram
- Participants
- Structural code in C# .{10}
- Real-world code in C# .{10}
- .NET Optimized code in C# .{10}
Summary: Without violating encapsulation, capture and externalize an object's internal state so that the object can be restored to this state later.
Frequency of use: Low
UML class diagram¶
Participants¶
The classes and objects participating in this pattern are:
- Memento (
Memento
) - stores internal state of the Originator object. The memento may store as much or as little of the originator's internal state as necessary at its originator's discretion.
- 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 access the memento's internal state.
- Originator (
SalesProspect
) - creates a memento containing a snapshot of its current internal state.
- uses the memento to restore its internal state
- Caretaker (
Caretaker
) - is responsible for the memento's safekeeping
- never operates on or examines the contents of a memento.
Structural code in C# .{10}¶
This structural code demonstrates the Memento pattern which temporary saves and restores another object's internal state.
using System;
namespace DoFactory.GangOfFour.Memento.Structural
{
/// <summary>
/// MainApp startup class for Structural
/// Memento Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
Originator o = new Originator();
o.State = "On";
// Store internal state
Caretaker c = new Caretaker();
c.Memento = o.CreateMemento();
// Continue changing originator
o.State = "Off";
// Restore saved state
o.SetMemento(c.Memento);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Originator' class
/// </summary>
class Originator
{
private string _state;
// Property
public string State
{
get { return _state; }
set
{
_state = value;
Console.WriteLine("State = " + _state);
}
}
// Creates memento
public Memento CreateMemento()
{
return (new Memento(_state));
}
// Restores original state
public void SetMemento(Memento memento)
{
Console.WriteLine("Restoring state...");
State = memento.State;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
class Memento
{
private string _state;
// Constructor
public Memento(string state)
{
this._state = state;
}
// Gets or sets state
public string State
{
get { return _state; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
class Caretaker
{
private Memento _memento;
// Gets or sets memento
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}
}
Output¶
Real-world code in C# .{10}¶
This real-world code demonstrates the Memento pattern which temporarily saves and then restores the SalesProspect's internal state.
using System;
namespace DoFactory.GangOfFour.Memento.RealWorld
{
/// <summary>
/// MainApp startup class for Real-World
/// Memento Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
SalesProspect s = new SalesProspect();
s.Name = "Noel van Halen";
s.Phone = "(412) 256-0990";
s.Budget = 25000.0;
// Store internal state
ProspectMemory m = new ProspectMemory();
m.Memento = s.SaveMemento();
// Continue changing originator
s.Name = "Leo Welch";
s.Phone = "(310) 209-7111";
s.Budget = 1000000.0;
// Restore saved state
s.RestoreMemento(m.Memento);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Originator' class
/// </summary>
class SalesProspect
{
private string _name;
private string _phone;
private double _budget;
// Gets or sets name
public string Name
{
get { return _name; }
set
{
_name = value;
Console.WriteLine("Name: " + _name);
}
}
// Gets or sets phone
public string Phone
{
get { return _phone; }
set
{
_phone = value;
Console.WriteLine("Phone: " + _phone);
}
}
// Gets or sets budget
public double Budget
{
get { return _budget; }
set
{
_budget = value;
Console.WriteLine("Budget: " + _budget);
}
}
// Stores memento
public Memento SaveMemento()
{
Console.WriteLine("\nSaving state --\n");
return new Memento(_name, _phone, _budget);
}
// Restores memento
public void RestoreMemento(Memento memento)
{
Console.WriteLine("\nRestoring state --\n");
this.Name = memento.Name;
this.Phone = memento.Phone;
this.Budget = memento.Budget;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
class Memento
{
private string _name;
private string _phone;
private double _budget;
// Constructor
public Memento(string name, string phone, double budget)
{
this._name = name;
this._phone = phone;
this._budget = budget;
}
// Gets or sets name
public string Name
{
get { return _name; }
set { _name = value; }
}
// Gets or set phone
public string Phone
{
get { return _phone; }
set { _phone = value; }
}
// Gets or sets budget
public double Budget
{
get { return _budget; }
set { _budget = value; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
class ProspectMemory
{
private Memento _memento;
// Property
public Memento Memento
{
set { _memento = value; }
get { return _memento; }
}
}
}
Output¶
Name: Noel van Halen
Phone: (412) 256-0990
Budget: 25000
Saving state --
Name: Leo Welch
Phone: (310) 209-7111
Budget: 1000000
Restoring state --
Name: Noel van Halen
Phone: (412) 256-0990
Budget: 25000
.NET Optimized code in C# .{10}¶
using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Soap;
namespace DoFactory.GangOfFour.Memento.NETOptimized
{
/// <summary>
/// MainApp startup class for .NET optimized
/// Memento Design Pattern.
/// </summary>
class MainApp
{
/// <summary>
/// Entry point into console application.
/// </summary>
static void Main()
{
// Init sales prospect through object initialization
var s = new SalesProspect
{
Name = "Joel van Halen",
Phone = "(412) 256-0990",
Budget = 25000.0
};
// Store internal state
var m = new ProspectMemory();
m.Memento = s.SaveMemento();
// Change originator
s.Name = "Leo Welch";
s.Phone = "(310) 209-7111";
s.Budget = 1000000.0;
// Restore saved state
s.RestoreMemento(m.Memento);
// Wait for user
Console.ReadKey();
}
}
/// <summary>
/// The 'Originator' class
/// </summary>
[Serializable]
class SalesProspect
{
private string _name;
private string _phone;
private double _budget;
// Gets or sets name
public string Name
{
get { return _name; }
set
{
_name = value;
Console.WriteLine("Name: " + _name);
}
}
// Gets or sets phone
public string Phone
{
get { return _phone; }
set
{
_phone = value;
Console.WriteLine("Phone: " + _phone);
}
}
// Gets or sets budget
public double Budget
{
get { return _budget; }
set
{
_budget = value;
Console.WriteLine("Budget: " + _budget);
}
}
// Stores (serializes) memento
public Memento SaveMemento()
{
Console.WriteLine("\nSaving state --\n");
var memento = new Memento();
return memento.Serialize(this);
}
// Restores (deserializes) memento
public void RestoreMemento(Memento memento)
{
Console.WriteLine("\nRestoring state --\n");
SalesProspect s = (SalesProspect)memento.Deserialize();
this.Name = s.Name;
this.Phone = s.Phone;
this.Budget = s.Budget;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
class Memento
{
private MemoryStream _stream = new MemoryStream();
private SoapFormatter _formatter = new SoapFormatter();
public Memento Serialize(object o)
{
_formatter.Serialize(_stream, o);
return this;
}
public object Deserialize()
{
_stream.Seek(0, SeekOrigin.Begin);
object o = _formatter.Deserialize(_stream);
_stream.Close();
return o;
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
class ProspectMemory
{
public Memento Memento { get; set; }
}
}