The Memento design pattern without violating encapsulation, captures and externalizes an object‘s internal state so that the object can be restored to this state later.
C# code examples of the Memento design pattern is provided in 3 forms:
A visualization of the classes and objects participating in this pattern.
The classes and objects participating in this pattern include:
Memento
)
SalesProspect
)
Caretaker
)
This structural code demonstrates the Memento pattern which temporary saves and restores another object's internal state.
using System;
namespace Memento.Structural
{
/// <summary>
/// Memento Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
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>
public class Originator
{
string state;
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>
public class Memento
{
string state;
// Constructor
public Memento(string state)
{
this.state = state;
}
public string State
{
get { return state; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
public class Caretaker
{
Memento memento;
public Memento Memento
{
set { memento = value; }
get { return memento; }
}
}
}
This real-world code demonstrates the Memento pattern which temporarily saves and then restores the SalesProspect's internal state.
using System;
namespace Memento.RealWorld
{
/// <summary>
/// Memento Design Pattern
/// </summary>
public class Program
{
public static void Main(string[] args)
{
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>
public class SalesProspect
{
string name;
string phone;
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");
Name = memento.Name;
Phone = memento.Phone;
Budget = memento.Budget;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
public class Memento
{
string name;
string phone;
double budget;
// Constructor
public Memento(string name, string phone, double budget)
{
this.name = name;
this.phone = phone;
this.budget = budget;
}
public string Name
{
get { return name; }
set { name = value; }
}
public string Phone
{
get { return phone; }
set { phone = value; }
}
public double Budget
{
get { return budget; }
set { budget = value; }
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
public class ProspectMemory
{
Memento memento;
public Memento Memento
{
set { memento = value; }
get { return memento; }
}
}
}
The .NET optimized code demonstrates the same code as above but uses
more modern C# and .NET features.
Here is an elegant C# Memento solution.
namespace Memento.NetOptimized;
using System.Text.Json;
using static System.Console;
/// <summary>
/// Memento Design Pattern
/// </summary>
public class Program
{
public 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(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
ReadKey();
}
}
/// <summary>
/// The 'Originator' class
/// </summary>
public class SalesProspect
{
private string name = null!;
private string phone = null!;
private double budget;
// Gets or sets name
public string Name
{
get => name;
set
{
name = value;
WriteLine("Name: " + name);
}
}
// Gets or sets phone
public string Phone
{
get => phone;
set
{
phone = value;
WriteLine("Phone: " + phone);
}
}
// Gets or sets budget
public double Budget
{
get => budget;
set
{
budget = value;
WriteLine("Budget: " + budget);
}
}
// Stores (serializes) memento
public Memento SaveMemento()
{
WriteLine("\nSaving state --\n");
var memento = new Memento();
return memento.Serialize(this);
}
// Restores (deserializes) memento
public void RestoreMemento(Memento memento)
{
WriteLine("\nRestoring state --\n");
var s = (SalesProspect)memento.Deserialize();
Name = s.Name;
Phone = s.Phone;
Budget = s.Budget;
}
}
/// <summary>
/// The 'Memento' class
/// </summary>
public class Memento
{
private string store = null!;
public Memento Serialize(object o)
{
store = JsonSerializer.Serialize(o);
return this;
}
public object Deserialize()
{
return JsonSerializer.Deserialize<SalesProspect>(store)!;
}
}
/// <summary>
/// The 'Caretaker' class
/// </summary>
public record ProspectMemory (Memento Memento);