نمط تذكاري
نمط التذكار هو نمط تصميم برمجي يعرض الحالة الداخلية الخاصة لكائن ما. ومن الأمثلة على كيفية استخدام هذا النمط استعادة كائن إلى حالته السابقة (التراجع عن طريق التراجع)، ومن الأمثلة الأخرى إصداره، ومن الأمثلة الأخرى التسلسل المخصص.
يتم تنفيذ نمط التذكار بثلاثة كائنات: المنشئ والقائم على الرعاية والتذكار . المنشئ هو بعض الكائنات التي لها حالة داخلية. سيقوم القائم على الرعاية بعمل شيء ما للمنشئ، لكنه يريد أن يكون قادرًا على التراجع عن التغيير. يطلب القائم على الرعاية أولاً من المنشئ كائن تذكار. ثم يقوم بأي عملية (أو تسلسل عمليات) كان سيفعلها. للتراجع إلى الحالة قبل العمليات، فإنه يعيد كائن التذكار إلى المنشئ. كائن التذكار نفسه هو كائن معتم (لا يمكن للقائم على الرعاية تغييره أو لا ينبغي له ذلك). عند استخدام هذا النمط، يجب توخي الحذر إذا كان المنشئ قد يغير كائنات أو موارد أخرى - يعمل نمط التذكار على كائن واحد.
تتضمن الأمثلة الكلاسيكية لنمط التذكار مولد أرقام عشوائية زائفة (يعمل كل مستهلك لمولد الأرقام العشوائية الزائفة كوصي يمكنه تهيئة مولد الأرقام العشوائية الزائفة (المنشئ) بنفس البذرة (التذكار) لإنتاج تسلسل متطابق من الأرقام العشوائية الزائفة) والحالة في آلة حالة محدودة.
بناء
مخطط فئة وتسلسل UML

في مخطط فئة UML أعلاه، Caretakerتشير الفئة إلى Originatorالفئة الخاصة بحفظ ( createMemento()) واستعادة ( restore(memento)).
تنفذ الفئة
(
1) عن طريق إنشاء كائن وإرجاعه يخزن الحالة الداخلية الحالية للمنشئ و
(2) عن طريق استعادة الحالة من الكائن المرسل.
OriginatorcreateMemento()Mementorestore(memento)Memento
يوضح مخطط تسلسل UML التفاعلات أثناء وقت التشغيل:
(1) حفظ الحالة الداخلية للمنشئ: Caretakerيستدعي الكائن الكائن createMemento()، Originatorالذي ينشئ Mementoكائنًا ويحفظ حالته الداخلية الحالية ( setState())، ويعيد Mementoإلى Caretaker.
(2) استعادة الحالة الداخلية للمنشئ: Caretakerيستدعي restore(memento)الكائن Originatorويحدد Mementoالكائن الذي يخزن الحالة التي يجب استعادتها. Originatorيحصل على الحالة ( getState()) من Mementoلتعيين حالته الخاصة.
مثال جافا
يوضح برنامج Java التالي استخدام "التراجع" لنمط التذكار.
import java.util.List ; import java.util.ArrayList ; class Originator { private String state ; // يمكن أن تحتوي الفئة أيضًا على بيانات إضافية ليست جزءًا من الحالة المحفوظة في التذكار.. public void set ( String state ) { this.state = state ; System.out.println ( "Originator: Setting state to " + state ) ; } public Memento saveToMemento () { System.out.println ( " Originator : Saving to Memento." ) ; return new Memento ( this.state ) ; } public void restoreFromMemento ( Memento memento ) { this.state = memento.getSavedState () ; System.out.println ( " Originator : State after restoreing from Memento : " + state ) ; } public static class Memento { private final String state ;
public Memento ( String stateToSave ) { state = stateToSave ; } // يمكن الوصول إليها من خلال الفئة الخارجية فقط private String getSavedState ( ) { return state ; } } } class Caretaker { public static void main ( String [ ] args ) { List < Originator.Memento > savedStates = new ArrayList < Originator.Memento > ( ); Originator originator = new Originator ( ); originator.set ( "State1" ); originator.set ( " State2" ) ; savedStates.add ( originator.saveToMemento ( ) ) ; originator.set ( " State3 " ); // يمكننا طلب تذكارات متعددة ، واختيار أي منها نريد الرجوع إليه . savedStates.add ( originator.saveToMemento ( ) ) ; originator.set ( " State4 " ) ; originator.restoreFromMemento ( saveStates.get ( 1 ) ) ; } }
المخرج هو:
المنشئ: تعيين الحالة إلى الحالة 1 المنشئ: تعيين الحالة إلى الحالة 2 المنشئ: الحفظ في Memento. المنشئ: تعيين الحالة إلى الحالة 3 المنشئ: الحفظ في Memento. المنشئ: تعيين الحالة إلى الحالة 4 المنشئ: الحالة بعد الاستعادة من Memento: الحالة 3
يستخدم هذا المثال String كحالة، وهي كائن غير قابل للتغيير في Java. في السيناريوهات الواقعية، ستكون الحالة دائمًا كائنًا قابلًا للتغيير، وفي هذه الحالة يجب عمل نسخة من الحالة.
يجب أن يقال إن التنفيذ الموضح به عيب: فهو يعلن عن فئة داخلية. سيكون من الأفضل أن يتم تطبيق استراتيجية التذكار هذه على أكثر من مصدر.
هناك ثلاث طرق أخرى رئيسية لتحقيق Memento:
- التسلسل.
- فئة معلنة في نفس الحزمة.
- يمكن أيضًا الوصول إلى الكائن عبر وكيل، والذي يمكنه تحقيق أي عملية حفظ/استعادة على الكائن.
مثال على لغة سي شارب
يتيح نمط التذكار التقاط الحالة الداخلية للكائن دون انتهاك التغليف بحيث يمكن التراجع عن التغييرات أو عكسها لاحقًا إذا لزم الأمر. هنا يمكن للمرء أن يرى أن كائن التذكار يستخدم بالفعل لعكس التغييرات التي تم إجراؤها على الكائن.
الفئة Memento { سلسلة خاصة للقراءة فقط savedState ؛
تذكار خاص ( سلسلة stateToSave ) { savedState = stateToSave ؛ }
public class Originator { private string state ; // يمكن أن تحتوي الفئة أيضًا على بيانات إضافية ليست جزءًا من الحالة المحفوظة في التذكار.
public void Set ( string state ) { Console.WriteLine ( " المنشئ : ضبط الحالة إلى " + state ) ; this.state = state ; }
public Memento SaveToMemento () { Console.WriteLine ( "المنشئ : الحفظ في Memento." ); return new Memento ( state ) ; }
public void RestoreFromMemento ( Memento memento ) { state = memento.saveState ; Console.WriteLine ( "المنشئ: الحالة بعد الاستعادة من Memento : " + state ) ; } } }
الفئة Caretaker { static void Main ( string [] args ) { var savedStates = new List <Memento> ( ) ;
var originator = new Memento.Originator ( ) ; originator.Set ( "State1" ); originator.Set ( " State2" ) ; savedStates.Add ( originator.SaveToMemento ( ) ); originator.Set ( " State3" ); // يمكننا طلب تذكارات متعددة ، واختيار أي منها نريد الرجوع إليه . savedStates.Add ( originator.SaveToMemento ( ) ) ; originator.Set ( " State4 " ) ;
المنشئ . RestoreFromMemento ( savedStates [ 1 ]);
} }
مثال بايثون
"
مثال على نمط التذكار.
"
الفئة الأصلية :
_state = ""
def set ( self ، state : str ) -> None :
print ( f "المنشئ: تعيين الحالة إلى { state } " )
self . _state = state
def save_to_memento ( self ) - > " Memento " :
إرجاع self.Memento ( self._state )
def restore_from_memento ( self , m : " Memento" ) - > None :
self._state = m.get_saved_state ( ) print ( f " المنشئ: الحالة بعد الاستعادة من Memento : { self._state } " )
الصف التذكاري :
def __init__ ( self , state ):
self . _state = state
def get_saved_state ( self )
: إرجاع self._state
saved_states = []
originator = Originator ()
originator . set ( "State1" )
originator . set ( "State2" )
saved_states . append ( originator . save_to_memento ())
المنشئ . set ( "State3" )
saved_states . append ( المنشئ . save_to_memento ())
المنشئ .set ( "State4 " )
المنشئ . restore_from_memento ( saved_states [ 1 ])
مثال جافا سكريبت
// يتم استخدام نمط Memento لحفظ واستعادة حالة الكائن.
// memento هي لقطة لحالة الكائن.
var Memento = { // Namespace: Memento savedState : null , // الحالة المحفوظة للكائن.
حفظ : دالة ( حالة ) { // حفظ حالة الكائن. this . savedState = state ; },
الاستعادة : دالة () { // استعادة حالة الكائن. return this . savedState ; } };
// المنشئ هو الكائن الذي ينشئ التذكار.
// يحدد طريقة لحفظ الحالة داخل التذكار.
var Originator = { // Namespace: Originator state : null , // الحالة التي سيتم تخزينها
// ينشئ منشئًا جديدًا بحالة أولية null
createMemento : function () { return { state : this.state // يتم نسخ الحالة إلى التذكار. }; } , setMemento : function ( memento ) { // يضبط حالة المنشئ من التذكار this.state = memento.state ; } } ;
// يخزن القائم بالرعاية تذكارات الكائنات
ويوفر العمليات لاسترجاعها.
var Caretaker = { // Namespace: Caretaker mementos : [], // تذكارات الكائنات. addMemento : function ( memento ) { // أضف تذكارًا إلى المجموعة. this . mementos . push ( memento ); }, getMemento : function ( index ) { // احصل على تذكار من المجموعة. return this . mementos [ index ]; } };
var action_step = "Foo" ; // الإجراء الذي سيتم تنفيذه/حالة الكائن التي سيتم تخزينها. var action_step_2 = "Bar" ; // الإجراء الذي سيتم تنفيذه/حالة الكائن التي سيتم تخزينها.
// تعيين الحالة الأولية
Originator . state = action_step ; Caretaker . addMemento ( Originator . createMemento ()); // حفظ الحالة في وحدة التحكم في السجل . log ( "Initial State: " + Originator . state ); // Foo
// تغيير الحالة Originator.state = action_step_2 ; Caretaker.addMemento ( Originator.createMemento ()); // حفظ الحالة في وحدة التحكم في السجل . log ( "State After Change: " + Originator.state ) ; // Bar
// استعادة الحالة الأولى - التراجع عن Originator.setMemento ( Caretaker.getMemento ( 0 ) ) ; console.log ( " الحالة بعد التراجع: " + Originator.state ) ; // Foo
// استعادة الحالة الثانية - إعادة
Originator . setMemento ( Caretaker . getMemento ( 1 ));
console . log ( "الحالة بعد إعادة: " + Originator . state ); // Bar
مراجع
- ^ "نمط تصميم Memento - البنية والتعاون". w3sDesign.com . تم الاسترجاع في 2017-08-12 .
روابط خارجية
- وصف نمط Memento في Ada
- مخطط فئة Memento UML مع عينات من أكواد C# و.NET
- دروس تعليمية حول إنشاء المصادر
- نمط تصميم Memento باستخدام Java
