الگوی Memento

الگوی Memento( خاطره) در دسته الگوهای رفتاری قرار دارد. بدون نقض کپسوله کردن، گرفتن و خارج کردن یک وضعیت داخلی در یک شیء، به طوری که بعدا می تواند به این وضعیت بازگردانده شود.به عبارت دیگر ذخیره سازی وضعیت شی در یک منبع خارجی به منظور احیا وضعیت آن در آینده بدون آن که اطلاعات خصوصی شی برملا شده یا از خصلت کپسوله سازی و پنهان سازی اطلاعات تخطی شود.UML class diagram شركت كنندگان کلاس ها و اشیاء شرکت کننده در این الگو عبارتند از:خاطره Memento (خاطره در مثال دنیای واقعی Memento):ذخیره وضعیت شی مبدا( Originator ).ممکن است در موارد ذکر شده ممکن است به اندازه و یا کمی از وضعیت داخلی در اختیار Originator قرار گیرد. محافظت در برابر دسترسی توسط اشیاء دیگر Originator. خاطره Mementos دو واسط (interface)موثر دارد.دستیار یک واسط محدود را به Memento می بیند - تنها می تواند به خاطره اشیا دیگر گذر کند. Originator ، در مقابل، واسط گسترده ای را می بیند، که اجازه می دهد تمام اطلاعات لازم برای بازگرداندن خود به وضعیت قبلی خود را داشته باشد. در حالت ایده آل، تنها originator که memento را تولید می کند، مجاز به دسترسی به وضعیت داخلی memento می باشد.به عبارت دیگر بسته اطلاعاتی یا خاطره‌ای است که وضعیت درونی Originator را در خود نگهداری می کند. با توجه به این که Originator وضعیت درونی و خصوصی خود را داخل Memento می گنجاند، Memento باید طوری طراحی شود که به جز Originator فرد دیگری نتواند آن را بردارد. یعنی محتویات Memento باید برای Originator شفاف و برای دیگران کدر باشد. مبدا-سازنده Originator (چشم انداز فروش SalesProspect) : یک Memento حاوی snapshot از وضعیت داخلی فعلی آن ایجاد می کند. خاطره Memento برای بازگرداندن وضعیت داخلی خود، از آن استفاده می کند.به عبارت دیگر کلاسی است که می‌خواهیم وضعیت درونی آن را حفظ کنیم. این کلاس متدی به نام CreateMemento() دارد که یک شئ Memento ایجاد می کند، وضعیت درونی خود را در آن قرار می دهد و شی ایجاد شده را برمیگرداند. همچنین متدی به نام SetMemento() دارد که یک Memento دریافت کرده و از طریق وضعیت درونی خودش را احیا می کند. سرپرست Caretaker (سرپرست Caretaker):مسئول نگهداری امن memento است. هرگز در محتویات یک memento عمل نمی کند یا بررسی نمی کند.به عبارت دیگر کلاسی است که:کاربر از او می‌خواهد وضعیت Originator را حفظ کند.سپس از Originator میخواهد وضعیتش را به شکل یک Memento به او بدهد.سپس شی Memento را نگهداری می کند.پس از آن درخواست احیا وضعیت شی Originator را از کاربر دریافت می کند.شی Memento مناسب را از محل ذخیره سازی اشیا Memento برمی دارد و به شی Originator میدهد و از او میخواهد وضعیت خودش را احیا کند.ساختار کلی کدالگوی Memento را نشان می دهد که به طور موقت موجب صرفه جویی و بازیابی وضعیت داخلی دیگر شی می شود. 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; } } } } OutputState = OnState = OffRestoring state:State = Onیا using System; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; public class Serializer { public static byte[] Serialize(object o) { var stream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize(stream, o); return stream.ToArray(); } public static object Deserialize(byte[] bytes) { var stream = new MemoryStream(); stream.Write(bytes, 0, bytes.Length); stream.Seek(0, SeekOrigin.Begin); var formatter = new BinaryFormatter(); var o = formatter.Deserialize(stream); stream.Close(); return o; } } public class TripleDESCryptographyConfig { private byte[] key; private byte[] iv; public byte[] Key { get { return key; } set { key = value; } } public byte[] IV { get { return iv; } set { iv = value; } } public TripleDESCryptographyConfig(string key, string iv) { this.key = UTF8Encoding.UTF8.GetBytes(key); this.iv = UTF8Encoding.UTF8.GetBytes(iv); } public TripleDESCryptographyConfig(byte[] key, byte[] iv) { this.key = key; this.iv = iv; } } public class TripleDESCryptography { public TripleDESCryptographyConfig Config { get; private set; } public TripleDESCryptography(TripleDESCryptographyConfig config) { this.Config = config; } public byte[] Encrypt(byte[] data) { byte[] result; var mStream = new MemoryStream(); var encyptor = new TripleDESCryptoServiceProvider().CreateEncryptor(Config.Key, Config.IV); var cStream = new CryptoStream(mStream, encyptor, CryptoStreamMode.Write); cStream.Write(data, 0, data.Length); cStream.FlushFinalBlock(); result = mStream.ToArray(); cStream.Close(); mStream.Close(); return result; } public byte[] Decrypt(byte[] data) { byte[] result; var mStream = new MemoryStream(data); var decryptor = new TripleDESCryptoServiceProvider().CreateDecryptor(Config.Key, Config.IV); var cStream = new CryptoStream(mStream, decryptor, CryptoStreamMode.Read); result = new byte[data.Length]; cStream.Read(result, 0, result.Length); cStream.Close(); mStream.Close(); return result; } } public class Originator { [Serializable] public class OriginatorState { public List<string> List { get; private set; } public string Name { get; private set; } public OriginatorState(List<string> list, string name) { this.List = list; this.Name = name; } } private TripleDESCryptography crypt; public string Name { get; private set; } private List<string> list = new List<string>(); private void Init(string name) { var config = new TripleDESCryptographyConfig("abcdefghijklmnopqrstuvwx", "12345678"); this.crypt = new TripleDESCryptography(config); this.Name = name; } public Originator() { Init(""); } public Originator(string name) { Init(name); } public void Append(string s) { list.Add(s); } public Memento CreateMemento() { var state = new OriginatorState(list, Name); var data = Serializer.Serialize(state); var encryptedData = crypt.Encrypt(data); return new Memento(encryptedData); } public void SetMemento(Memento m) { var decryptedData = crypt.Decrypt(m.Data); var data = (OriginatorState)Serializer.Deserialize(decryptedData); list = data.List; Name = data.Name; } public void Print() { foreach (var s in list) { Console.WriteLine(s); } Console.WriteLine(); } } public class Memento { public byte[] Data { get; private set; } public Memento(byte[] data) { this.Data = data; } public byte[] GetState() { return this.Data; } } public class Test { public static void Main() { var originator1 = new Originator("Originator"); originator1.Append("List of Programming Languages\n"); originator1.Append("C++"); originator1.Append("Java"); originator1.Append("C#"); originator1.Append("Python"); originator1.Append("Groovy"); originator1.Append("Ruby"); var memento = originator1.CreateMemento(); var originator2 = new Originator(); originator2.SetMemento(memento); originator2.Print(); Console.ReadKey(); } } /* OUTPUT:List of Programming LanguagesC++JavaC#PythonGroovyRuby*/منبع