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 ); } } }