
الگوی طراحـــــــــی Memento
الگوی طراحی Memento یک الگوی رایج در برنامهنویسی است که برای ذخیره و بازیابی حالت یک شیء (Object) به کار میرود. این الگو به ما امکان میدهد که یک نسخه از حالت یک شیء را ذخیره کنیم و در زمان لازم، از آن نسخه برای بازیابی حالت شیء استفاده کنیم. از این الگو زمانی استفاده میشود که میخواهیم تغییراتی که در یک شیء انجام میدهیم قابل بازگشت باشد و یا به عبارتی، ما میتوانیم به حالت قبلی شیء بازگردیم.
الگوی طراحی Memento بدون نقض انکپسولیشن، حالت داخلی یک شی را ضبط و برون سازی می کند تا بتواند بعداً به این حالت بازگردد.
سختش نکنیم! تابحال به عملکرد Undo دقت کردید؟ هر وقت بخوایم میتونیم یک مرحله کارمون رو به عقب برگردونیم. این دقیقا همین دیزاین پترنه! هروقت میخوای وضعیت هایی رو نگهداری کنی که هروقت خواستی بتونی به عقب برگردی (نه صرفا یکی یکی عقب بری، هر وضعیتی که خواستی میتونی بری) از این دیزاین پترن استفاده میکنیم.
مفهوم الگوی Memento به این صورت است که ما یک کلاس Memento داریم که حالت شیء را ذخیره میکند و یک کلاس Originator داریم که حالت شیء را تغییر میدهد. سپس یک کلاس Caretaker نیز وجود دارد که از کلاس Memento استفاده میکند تا حالت شیء را ذخیره کند و از آن برای بازیابی حالت استفاده کند.
معمولاً اجزاء اصلی الگوی طراحی Memento شامل موارد زیر هستند:
1. Memento: کلاسی است که حالت یک شیء را ذخیره میکند.
2. Originator: کلاسی است که حالت شیء را تغییر میدهد و یا از حالت Memento بازیابی میکند.
3. Caretaker: کلاسی است که از کلاس Memento استفاده میکند تا حالت شیء را ذخیره کند و از آن برای بازیابی حالت استفاده کند.
برای درک بهتر این الگو، با یک مثال ملموس و کاربردی در دنیای واقعی آشنا میشویم:
فرض کنید ما یک برنامهی ویرایشگر متن ساده داریم که متن ورودی را ویرایش میکند. میخواهیم امکان بازگشت به وضعیت قبلی متن را فراهم کنیم. در این صورت از الگوی Memento استفاده میکنیم تا حالتهای مختلف متن را ذخیره کنیم و به وضعیتهای قبلی بازگردیم.
حالا بیایید کد مربوط به این مثال را در زبان سی شارپ بنویسیم:
1. Memento:
1public class TextMemento
2{
3 public string Text { get; }
4
5 public TextMemento(string text)
6 {
7 Text = text;
8 }
9}
2. Originator:
1public class TextEditor
2{
3 private string _text;
4
5 public string Text
6 {
7 get { return _text; }
8 set
9 {
10 _text = value;
11 Console.WriteLine($"Text set to: {_text}");
12 }
13 }
14
15 public TextMemento CreateMemento()
16 {
17 return new TextMemento(_text);
18 }
19
20 public void RestoreMemento(TextMemento memento)
21 {
22 _text = memento.Text;
23 Console.WriteLine($"Text restored to: {_text}");
24 }
25}
3. Caretaker:
1public class TextEditorHistory
2{
3 private Stack<TextMemento> _history = new Stack<TextMemento>();
4
5 public void Save(TextMemento memento)
6 {
7 _history.Push(memento);
8 }
9
10 public TextMemento Undo()
11 {
12 return _history.Pop();
13 }
14}
4. Client (کلاینت):
1public class Program
2{
3 public static void Main()
4 {
5 TextEditor editor = new TextEditor();
6 TextEditorHistory history = new TextEditorHistory();
7
8 editor.Text = "Hello, world!";
9 history.Save(editor.CreateMemento());
10
11 editor.Text = "Welcome to the Memento pattern!";
12 history.Save(editor.CreateMemento());
13
14 editor.Text = "Design patterns are awesome!";
15 history.Save(editor.CreateMemento());
16
17 // بازگردانی به حالت قبلی
18 editor.RestoreMemento(history.Undo()); // خروجی: Text restored to: Design patterns are awesome!
19 editor.RestoreMemento(history.Undo()); // خروجی: Text restored to: Welcome to the Memento pattern!
20 }
21}
در این مثال، با استفاده از الگوی Memento، ما امکان بازگشت به وضعیتهای قبلی متن را فراهم کردیم. کلاس `TextEditor` که به عنوان Originator عمل میکند، حالت متن را به صورت رشتهای ذخیره میکند و از طریق تابعهای `CreateMemento()` و `RestoreMemento()` این حالتها را ذخیره و بازیابی میکند. کلاس `TextEditorHistory` نیز به عنوان Caretaker عمل میکند و تمامی نسخههای ذخیرهشده را در یک پشته نگه میدارد. هرگاه نیاز به بازگشت به وضعیت قبلی متن داشته باشیم، از تابع `Undo()` در کلاس `TextEditorHistory` استفاده میکنیم تا آخرین حالت ذخیرهشده را از پشته بازیابی کنیم و با استفاده از تابع `RestoreMemento()` در کلاس `TextEditor` حالت متن را به وضعیت قبلی بازگردانی کنیم.
خروجی برنامه به صورت زیر خواهد بود:
Text set to: Hello, world!
Text set to: Welcome to the Memento pattern!
Text set to: Design patterns are awesome!
Text restored to: Design patterns are awesome!
Text restored to: Welcome to the Memento pattern!
در این مثال، متن ابتدا به "Hello, world!" تغییر داده شده و سپس دو بار تغییرات دیگری اعمال میشود و هر بار حالتها با تابع `Save()` در کلاس `TextEditorHistory` ذخیره میشوند. سپس با استفاده از تابع `Undo()`، متن به وضعیتهای قبلی بازگردانده میشود. این نشان میدهد که با استفاده از الگوی Memento میتوانیم تغییرات را بازنگری کنیم و به حالتهای قبلی برگردیم.