Object Oriented Programming Patterns for Geeks
The Memento Pattern
namespace ooppatterns
{
using System;
using System.Collections.Generic;
using System.Reflection;
internal class Program
{
private static void Main( string[] args )
{
CustomerData CD = new CustomerData( "Mr", "Matt", "Warren" );
CD.Email = "matt@foo.com";
Memento<CustomerData> mem = new Memento<CustomerData>();
//try
//{
// temporaily store object
mem.Store( CD );
// Attempt update
CD.Email = "fizz@bang.com";
// if there are no errors... continue...
//}
//catch
//{
// If there is an error, restore object to previous state
mem.Restore( CD );
//}
Console.WriteLine();
//try
//{
// temporaily store object
CD.Store( mem );
// Attempt update
CD.Email = "someone@somewhere.com";
// if there are no errors... continue...
//}
//catch
//{
// If there is an error, restore object to previous state
CD.Restore( mem );
//}
Console.ReadLine();
}
}
interface IStorable<T>
where T : class
{
void Store( Memento<T> item );
void Restore( Memento<T> item );
}
class Memento<T>
where T : class
{
private const BindingFlags BINDINGS
= BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
private Dictionary<int, Dictionary<string, object>> _storeage;
public Memento()
{
this._storeage = new Dictionary<int, Dictionary<string, object>>();
}
public void Store( T item )
{
if ( this._storeage.ContainsKey( item.GetHashCode() ) )
throw new InvalidOperationException(
"Object supplied is already stored!" );
Dictionary<string, object> _data = new Dictionary<string, object>();
FieldInfo[] FIs = typeof( T ).GetFields( BINDINGS );
foreach ( FieldInfo FI in FIs )
_data.Add( FI.Name, FI.GetValue( item ) );
this._storeage.Add( item.GetHashCode(), _data );
Console.WriteLine( " OBJECT STATE STORED : {0}", item.ToString() );
}
public void Restore( T item )
{
if ( !this._storeage.ContainsKey( item.GetHashCode() ) )
throw new InvalidOperationException(
"Object supplied is does not have any stored data!" );
Console.WriteLine( "STATE BEFORE RESTORE : {0}", item.ToString() );
Dictionary<string, object> _data = this._storeage[item.GetHashCode()];
foreach ( string field in _data.Keys )
{
FieldInfo FI = typeof( T ).GetField( field, BINDINGS );
FI.SetValue( item, _data[field] );
}
this._storeage.Remove( item.GetHashCode() );
Console.WriteLine( " STATE AFTER RESTORE : {0}", item.ToString() );
}
}
class CustomerData : IStorable<CustomerData>
{
private string _title = @"";
private string _forename = @"";
private string _surname = @"";
private string _email = @"";
private string _phone = @"";
private string _cellular = @"";
public CustomerData( string title, string forename, string surname )
{
this._title = title;
this._forename = forename;
this._surname = surname;
}
public string Title
{
get { return this._title; }
set { this._title = value; }
}
public string Forename
{
get { return this._forename; }
set { this._forename = value; }
}
public string Surname
{
get { return this._surname; }
set { this._surname = value; }
}
public string Email
{
get { return this._email; }
set { this._email = value; }
}
public string Phone
{
get { return this._phone; }
set { this._phone = value; }
}
public string Cellular
{
get { return this._cellular; }
set { this._cellular = value; }
}
// Store data...
public void Store( Memento<CustomerData> item )
{
item.Store( this );
}
// Restore data
public void Restore( Memento<CustomerData> item )
{
item.Restore( this );
}
public override string ToString()
{
return string.Format( "{0} {1} {2}, {3} {4} {5}",
this._title, this._forename, this._surname,
this._email, this._phone, this._cellular );
}
}
}