تم اقتراح وضع Observer ، المعروف أيضًا باسم وضع النشر/الاشتراك ، من قبل المجموعة المكونة من أربعة أشخاص (GOF ، وهي Erich Gamma و Richard Helm و Ralph Johnson و John Vlissides) في "نمط التصميم: The Basics of Resulable Comply Orgening" (انظر الصفحات 293-313 في كتاب التفاصيل). على الرغم من أن هذا النمط له تاريخ كبير ، إلا أنه لا يزال ينطبق على نطاق واسع على مجموعة متنوعة من السيناريوهات ، وقد أصبح جزءًا لا يتجزأ من مكتبة Java القياسية. على الرغم من وجود الكثير من المقالات حول أنماط المراقب ، إلا أنها تركز جميعها على التنفيذ في Java ، ولكنها تتجاهل مختلف المشكلات التي يواجهها المطورين عند استخدام أنماط المراقب في Java.
تتمثل القصد الأصلي لكتابة هذه المقالة في ملء هذه الفجوة: تقدم هذه المقالة بشكل أساسي تنفيذ نمط المراقب باستخدام بنية Java8 ، ويستكشف المزيد من المشكلات المعقدة حول الأنماط الكلاسيكية على هذا الأساس ، بما في ذلك الفصول الداخلية المجهولة ، وتعبيرات Lambda ، وسلامة الرسائل ، وتنفيذ مراقب غير مهذب للوقت. على الرغم من أن محتوى هذه المقالة غير شامل ، إلا أنه لا يمكن تفسير العديد من المشكلات المعقدة التي ينطوي عليها هذا النموذج في مقالة واحدة فقط. ولكن بعد قراءة هذا المقال ، يمكن للقراء فهم ماهية نمط المراقب ، وعالميته في Java ، وكيفية التعامل مع بعض المشكلات الشائعة عند تنفيذ نمط المراقب في Java.
وضع المراقب
وفقًا للتعريف الكلاسيكي الذي اقترحه GOF ، فإن موضوع نمط المراقب هو:
يحدد التبعية الواحدة بين الكائنات. عندما تتغير حالة الكائن ، يتم إخطار جميع الكائنات التي تعتمد عليه وتحديثها تلقائيًا.
ماذا يعني ذلك؟ في العديد من تطبيقات البرامج ، تكون الحالات بين الكائنات مترابطة. على سبيل المثال ، إذا كان التطبيق يركز على معالجة البيانات العددية ، فقد يتم عرض هذه البيانات من خلال الجداول أو المخططات لواجهة المستخدم الرسومية (GUI) أو المستخدمة في نفس الوقت ، أي عند تحديث البيانات الأساسية ، يجب أيضًا تحديث مكونات واجهة المستخدم الرسومية المقابلة. مفتاح المشكلة هو كيفية تحديث البيانات الأساسية عند تحديث مكونات واجهة المستخدم الرسومية ، وفي الوقت نفسه تقلل من الاقتران بين مكونات واجهة المستخدم الرسومية والبيانات الأساسية.
يتمثل الحل البسيط وغير القابل للتطبيق في الإشارة إلى مكونات واجهة المستخدم الرسومية للمعلومات التي تدير هذه البيانات الأساسية ، بحيث يمكن للكائنات إخطار مكونات واجهة المستخدم الرسومية عند تغيير البيانات الأساسية. من الواضح أن هذا الحل البسيط أظهر بسرعة أوجه القصور في التطبيقات المعقدة التي تتعامل مع المزيد من مكونات واجهة المستخدم الرسومية. على سبيل المثال ، هناك 20 مكونًا من مكونات واجهة المستخدم الرسومية تعتمد جميعها على البيانات الأساسية ، وبالتالي فإن الكائنات التي تدير البيانات الأساسية تحتاج إلى الحفاظ على هذه المكونات العشرين. مع زيادة عدد الكائنات التي تعتمد على البيانات ذات الصلة ، يصعب التحكم في درجة الاقتران بين إدارة البيانات والكائنات.
حل آخر أفضل هو السماح للكائنات بالتسجيل للحصول على أذونات لتحديث البيانات ذات الاهتمام ، والتي يقوم مدير البيانات بإخطار هذه الكائنات عند تغيير البيانات. بشروط Layman ، دع كائن البيانات ذي الاهتمام يخبر المدير: "يرجى إخطارني عندما تتغير البيانات". بالإضافة إلى ذلك ، لا يمكن لهذه الكائنات التسجيل فقط للحصول على إشعارات التحديث ، ولكن أيضًا إلغاء التسجيل للتأكد من أن مدير البيانات لم يعد يخطر الكائن عند تغيير البيانات. في التعريف الأصلي لـ GOF ، يسمى الكائن المسجل للحصول على تحديثات "Observer" ، ويسمى مدير البيانات المقابل "الموضوع" ، والبيانات التي يهتم بها المراقب تسمى "الحالة المستهدفة" ، وتسمى عملية التسجيل "ADD" وعملية مراقبة التراجع تسمى "disach". كما ذكر أعلاه ، يسمى وضع المراقب أيضًا وضع النشر. يمكن فهم أن العميل يشترك في المراقب حول الهدف. عند تحديث الحالة المستهدفة ، ينشر الهدف هذه التحديثات إلى المشترك (يتم تمديد نمط التصميم هذا إلى بنية عامة ، تسمى بنية النشر-الاشتراك). يمكن تمثيل هذه المفاهيم من خلال الرسم البياني للصف التالي:
يستخدمه فيما يتعلق بتلقي تغييرات حالة التحديث وتمرير مرجع إلى exeretesubject إلى مُنشئه. يوفر هذا إشارة إلى موضوع معين لمراقب معين ، يمكن من خلاله الحصول على التحديثات عندما تتغير الحالة. ببساطة ، سيتم إخبار المراقب المحدد بتحديث الموضوع ، وفي الوقت نفسه ، استخدم المراجع في مُنشئه للحصول على حالة الموضوع المحدد ، وأخيراً تخزين كائنات حالة البحث هذه ضمن خاصية ObserverState للمراقب المحدد. تظهر هذه العملية في مخطط التسلسل التالي:
احتراف النماذج الكلاسيكية
على الرغم من أن نموذج المراقب عالمي ، إلا أن هناك العديد من النماذج المتخصصة ، والأكثر شيوعًا هي الاثنان التاليين:
يوفر معلمة لكائن الحالة ، تم تمريرها إلى طريقة التحديث التي يطلق عليها المراقب. في الوضع الكلاسيكي ، عندما يتم إخطار المراقب بأن حالة الموضوع قد تغيرت ، سيتم الحصول على حالتها المحدثة مباشرة من الموضوع. هذا يتطلب من المراقب حفظ مرجع كائن إلى الحالة التي تم استردادها. هذا يشكل مرجعًا دائريًا ، يشير مرجع concretesubject إلى قائمة المراقبين الخاصة به ، ويشير مرجع ConcreteObserver إلى concretesubject التي يمكن أن تحصل على حالة الموضوع. بالإضافة إلى الحصول على الحالة المحدثة ، لا يوجد أي صلة بين المراقب والموضوع الذي يسجله للاستماع إليه. يهتم المراقب بكائن الدولة ، وليس الموضوع نفسه. وهذا يعني ، في كثير من الحالات ، ترتبط ConcreteObserver و concretesubject معًا بالقوة. على العكس من ذلك ، عندما يستدعي concretesubject وظيفة التحديث ، يتم تمرير كائن الحالة إلى ConcreteObserver ، ولا يحتاج الاثنان إلى ربطهما. إن العلاقة بين ConcreteObserver و STATE COSTER تقلل من درجة الاعتماد بين المراقب والدولة (انظر مقالة Martin Fowler لمزيد من الاختلافات في الارتباط والاعتماد).
دمج الفئة التجريدية الموضوع و concretesubject في فئة الفردية. في معظم الحالات ، لا يؤدي استخدام الفئات المجردة في الموضوع إلى تحسين مرونة البرنامج وقابليته للتوسع ، لذا فإن الجمع بين هذه الفئة المجردة والفئة الملموسة يبسط التصميم.
بعد الجمع بين هذين النموذجين المتخصصين ، يكون مخطط الفئة المبسط كما يلي:
في هذه النماذج المتخصصة ، يتم تبسيط بنية الطبقة الثابتة بشكل كبير ويتم تبسيط التفاعلات بين الفئات. مخطط التسلسل في هذا الوقت هو كما يلي:
ميزة أخرى في وضع التخصص هي إزالة المتغير الأعضاء من ConcreteObserver. في بعض الأحيان ، لا يحتاج المراقب المحدد إلى حفظ أحدث حالة من الموضوع ، ولكن يحتاج فقط إلى مراقبة حالة الموضوع عند تحديث الحالة. على سبيل المثال ، إذا قام المراقب بتحديث قيمة متغير العضو إلى الإخراج القياسي ، فيمكنه حذف ObserVerState ، الذي يزيل الارتباط بين ConcreteObserver وفئة الحالة.
قواعد التسمية الأكثر شيوعا
يستخدم النموذج الكلاسيكي وحتى النموذج المهني المذكور أعلاه مصطلحات مثل Attance و Detach and Observer ، في حين أن العديد من تطبيقات Java تستخدم قواميس مختلفة ، بما في ذلك التسجيل ، غير المسجلة ، المستمع ، إلخ. تجدر الإشارة إلى أن الحالة هي مصطلح عام لجميع الكائنات التي يحتاج المستمع إلى مراقبة التغييرات. يعتمد الاسم المحدد لكائن الحالة على السيناريو المستخدم في وضع المراقب. على سبيل المثال ، في وضع المراقب في المشهد حيث يستمع المستمع إلى حدوث الحدث ، سيتلقى المستمع المسجل إشعارًا عند حدوث الحدث. كائن الحالة في هذا الوقت هو الحدث ، أي ما إذا كان الحدث قد حدث.
في التطبيقات الفعلية ، نادراً ما يتضمن تسمية الأهداف موضوعًا. على سبيل المثال ، قم بإنشاء تطبيق حول حديقة الحيوان ، وتسجيل مستمعين متعددين لمراقبة فئة حديقة الحيوان ، وتلقي الإخطارات عندما تدخل الحيوانات الجديدة إلى حديقة الحيوان. الهدف في هذه الحالة هو فئة حديقة الحيوان. من أجل الحفاظ على المصطلحات متسقة مع مجال المشكلة المحدد ، لن يتم استخدام مصطلح "الموضوع" ، مما يعني أنه لن يتم تسمية فئة حديقة الحيوان.
يتبع تسمية المستمع عمومًا لاحقة المستمع. على سبيل المثال ، سيتم تسمية المستمع المذكور أعلاه لمراقبة الحيوانات الجديدة. وبالمثل ، فإن تسمية الوظائف مثل التسجيل ، وعدم التسجيل والإخطار غالباً ما يتم احتسابها بأسماء المستمعين المقابلة. على سبيل المثال ، سيتم تسمية السجل ، غير المسجلة ، وإخطار وظائف animaladdedlistener. تجدر الإشارة إلى أنه يتم استخدام اسم وظيفة الإخطار ، لأن دالة الإخطار تتعامل مع مستمعين متعددين بدلاً من مستمع واحد.
ستظهر طريقة التسمية هذه طويلة ، وعادة ما يسجل الموضوع أنواعًا متعددة من المستمعين. على سبيل المثال ، في مثال حديقة الحيوان المذكورة أعلاه ، في حديقة الحيوان ، بالإضافة إلى تسجيل مستمعين جدد لمراقبة الحيوانات ، يحتاج أيضًا إلى تسجيل مستمع للحيوانات لتقليل المستمعين. في هذا الوقت ، ستكون هناك وظيفتان للتسجيل: (RecordAnimalAddedListener و RecordAnimalRemovedListener. وبهذه الطريقة ، يتم استخدام نوع المستمع كأحد المؤهلات للإشارة إلى نوع المراقب. حل آخر هو إنشاء وظيفة قائمة تسجيل ، ثم تحمله الزائد ، ولكن الحل 1 يمكن أن يعرف بشكل أكثر سهولة الاستماع.
هناك بناء جملة Idiomatic آخر هو استخدام البادئة بدلاً من التحديث ، على سبيل المثال ، تتم تسمية وظيفة التحديث onanimaladded بدلاً من updateanimaladded. يكون هذا الموقف أكثر شيوعًا عندما يحصل المستمع على إشعارات للتسلسل ، مثل إضافة حيوان إلى القائمة ، ولكن نادراً ما يتم استخدامه لتحديث بيانات منفصلة ، مثل اسم الحيوان.
بعد ذلك ، ستستخدم هذه المقالة قواعد Java الرمزية. على الرغم من أن القواعد الرمزية لن تغير التصميم الحقيقي وتنفيذ النظام ، إلا أنه من المهم مبدأ تطوير مهم لاستخدام المصطلحات التي يعرفها المطورين الآخرون ، لذلك يجب أن تكون على دراية بقواعد نمط المراقب في Java الموصوفة أعلاه. سيتم شرح المفهوم أعلاه أدناه باستخدام مثال بسيط في بيئة Java 8.
مثال بسيط
إنه أيضًا مثال حديقة الحيوان المذكورة أعلاه. باستخدام واجهة API من JAVA8 لتنفيذ نظام بسيط ، يشرح المبادئ الأساسية لنمط المراقب. تم وصف المشكلة على النحو التالي:
قم بإنشاء حديقة حيوان نظام ، مما يتيح للمستخدمين الاستماع والتراجع عن حالة إضافة كائن جديد للحيوان ، وإنشاء مستمع معين ، مسؤول عن إخراج اسم الحيوان الجديد.
وفقًا للتعلم السابق لنمط المراقب ، نعلم أنه لتنفيذ مثل هذا التطبيق ، نحتاج إلى إنشاء 4 فئات ، على وجه التحديد:
فئة حديقة الحيوان: أي الموضوع في النمط ، وهو مسؤول عن تخزين جميع الحيوانات في حديقة الحيوان وإخطار جميع المستمعين المسجلين عند انضمام الحيوانات الجديدة.
طبقة الحيوان: يمثل كائن حيوان.
فئة AnimalAddedListener: أي ، واجهة المراقب.
printnameanimaladdedlistener: فئة المراقب المحددة هي المسؤولة عن إخراج اسم الحيوان المضافة حديثًا.
أولاً ، نقوم بإنشاء فئة حيوانية ، وهو كائن Java بسيط يحتوي على متغيرات العضو ، والمصممون ، و Getters وطرق Setter. الرمز كما يلي:
الفئة العامة Animal {private string name ؛ public Animal (اسم السلسلة) {this.name = name ؛} السلسلة العامة getName () {return this.name ؛استخدم هذه الفئة لتمثيل الأشياء الحيوانية ، وبعد ذلك يمكنك إنشاء واجهة AnimalAddedListener:
الواجهة العامة animaladdedlistener {public void onanimaladded (Animal Animal) ؛}الفئتين الأولين بسيطان للغاية ، لذلك لن أقدمهما بالتفصيل. بعد ذلك ، قم بإنشاء فئة حديقة الحيوان:
Zoo Class Public {Private List <Inmal> leuties = new ArrayList <> () ؛ قائمة خاصة <AntamentDedListener> المستمعين = جديد ArrayList <> () ؛ public void addanimal (Animal Animal) {// add the animal to the legantymalaDded ؛ registerAnimalAddedListener (مستمع AnimalAddedListener) {// أضف المستمع إلى قائمة المستمعين المسجلين. itferanimaladdedlisteners (Animal Animal) {// إخطار كل من المستمعين في قائمة المستمعين المسجلين المستمعين.هذا القياس معقد من السابقين. يحتوي على قائمتين ، يتم استخدام إحداها لتخزين جميع الحيوانات في حديقة الحيوان والآخر يستخدم لتخزين جميع المستمعين. بالنظر إلى أن الكائنات المخزنة في الحيوانات ومجموعات المستمع بسيطة ، فقد اختارت هذه المقالة ArrayList للتخزين. يعتمد بنية البيانات المحددة للمستمع المخزن على المشكلة. على سبيل المثال ، بالنسبة لمشكلة حديقة الحيوان هنا ، إذا كان للمستمع الأولوية ، فيجب عليك اختيار بنية بيانات أخرى ، أو إعادة كتابة خوارزمية سجل المستمع.
يعد تنفيذ التسجيل والإزالة على حد سواء طريقة مندوب بسيط: تتم إضافة أو إزالة كل مستمع من قائمة الاستماع للمستمع كمعلمة. يتم تنفيذ وظيفة الإخطار قليلاً عن التنسيق القياسي لنمط المراقب. ويشمل معلمة الإدخال: الحيوان الذي تمت إضافته حديثًا ، بحيث يمكن لدالة الإخطار أن تمرر مرجع الحيوانات المضافة حديثًا إلى المستمع. استخدم وظيفة foreach من واجهة برمجة تطبيقات التدفقات لاجتياز المستمعين وتنفيذ وظيفة theonanimaladded على كل مستمع.
في وظيفة Addanimal ، تتم إضافة الكائن الحيواني والمستمع المضافة حديثًا إلى القائمة المقابلة. إذا لم يتم أخذ تعقيد عملية الإخطار في الاعتبار ، فيجب تضمين هذا المنطق في طريقة مكالمة مريحة. ما عليك سوى المرور في إشارة إلى الكائن الحيوانية المضافة حديثًا. هذا هو السبب في أن التنفيذ المنطقي لمستمع الإخطار مغلف في دالة الإخطارات.
بالإضافة إلى القضايا المنطقية المتمثلة في الإخطار ، من الضروري التأكيد على القضية المثيرة للجدل حول رؤية وظائف الإخطار. في نموذج المراقب الكلاسيكي ، كما قال GOF في الصفحة 301 من أنماط تصميم الكتب ، فإن وظيفة الإخطار عامة ، ولكن على الرغم من استخدامها في النمط الكلاسيكي ، فإن هذا لا يعني أنه يجب أن يكون عامًا. يجب أن يعتمد اختيار الرؤية على التطبيق. على سبيل المثال ، في مثال حديقة حيوان هذه المقالة ، تكون وظيفة الإخطار من النوع المحمي ولا تتطلب كل كائن لبدء إشعار مراقب مسجل. يحتاج فقط إلى التأكد من أن الكائن يمكن أن يرث الوظيفة من الفئة الأصل. بالطبع ، هذا ليس هو الحال بالضبط. من الضروري معرفة الفئات التي يمكنها تنشيط وظيفة الإخطار ، ثم تحديد رؤية الوظيفة.
بعد ذلك ، تحتاج إلى تنفيذ فئة printnameanimaladdedlistener. تستخدم هذه الفئة طريقة system.out.println لإخراج اسم الحيوان الجديد. الرمز المحدد كما يلي:
الطبقة العامة printnameanimaladdedlistener تنفذ animaladdedistener {Overridepublic void updateanimaladded (Animal Animal) {// print the the the the the sestem.out.println (}}}أخيرًا ، نحتاج إلى تنفيذ الوظيفة الرئيسية التي تدفع التطبيق:
الفئة العامة الرئيسية {public static void main (string [] args) {// إنشاء حديقة الحيوان لتخزين eleventzoo zoo = new zoo () ؛ // تسجيل مستمع ليتم إخطاره عند إضافة حيوان. حيوان ("نمر")) ؛}}تقوم الوظيفة الرئيسية ببساطة بإنشاء كائن حديقة للحيوانات ، ويسجل مستمعًا يخرج اسم الحيوان ، ويقوم بإنشاء كائن حيوان جديد لدفع المستمع المسجل. الإخراج النهائي هو:
أضاف حيوان جديد يحمل اسم "النمر"
أضاف المستمع
يتم عرض مزايا وضع المراقب بالكامل عند إعادة تأسيس المستمع وإضافته إلى الموضوع. على سبيل المثال ، إذا كنت ترغب في إضافة مستمع يحسب العدد الإجمالي للحيوانات في حديقة الحيوان ، فأنت بحاجة فقط إلى إنشاء فئة مستمع معينة وتسجيله في فئة حديقة الحيوان دون أي تعديل لفئة حديقة الحيوان. إن إضافة رمز CountingAnimalAddedListener هو على النحو التالي:
الطبقة العامة countinganimaladdedlistener تنفذ animaladdedistener {private static int eleventsaddedcount = 0 ؛ Overridepublic void updateanimaladded (Animal Animal) {// زيادة عدد الحيوانات.الوظيفة الرئيسية المعدلة هي كما يلي:
الفئة العامة الرئيسية {public static void main (string [] args) {// إنشاء حديقة الحيوان لتخزين eleventzoo zoo = new zoo () ؛ // تسجيل المستمعين ليتم إخطارهم عند إضافة حيوان إبلاغ المستمعين المسجلين. addanimal (حيوان جديد ("Tiger")) ؛ Zoo.Addanimal (حيوان جديد ("Lion")) ؛ Zoo.Addanimal (حيوان جديد ("Bear")) ؛}}نتيجة الإخراج هي:
تمت إضافة حيوان جديد يحمل اسم "Tiger" إجمالي الحيوانات: أضيف 1 حيوانًا جديدًا باسم "أسد" الحيوانات الإجمالية المضافة: 2 أضاف حيوانًا جديدًا باسم "Bear" الحيوانات الإجمالية المضافة: 3
يمكن للمستخدم إنشاء أي مستمع إذا قام فقط بتعديل رمز تسجيل المستمع. هذا قابلية التوسع ترتبط بشكل أساسي بموضوع المراقب ، بدلاً من المرتبطة مباشرة بـ ConcreteObserver. طالما لم يتم تعديل الواجهة ، فليس هناك حاجة لتعديل موضوع الواجهة.
فصول داخلية مجهولة ، وظائف Lambda وتسجيل المستمع
أحد التحسنات الرئيسية في Java 8 هو إضافة الميزات الوظيفية ، مثل إضافة وظائف Lambda. قبل تقديم وظيفة Lambda ، قدمت Java وظائف مماثلة من خلال فئات داخلية مجهولة المصدر ، والتي لا تزال تستخدم في العديد من التطبيقات الموجودة. في وضع Observer ، يمكن إنشاء مستمع جديد في أي وقت دون إنشاء فصل مراقب معين. على سبيل المثال ، يمكن تنفيذ فئة printnameanimaladdedlistener في الوظيفة الرئيسية مع فئة داخلية مجهولة المصدر. رمز التنفيذ المحدد كما يلي:
الفئة العامة الرئيسية {public static void main (string [] args) {// إنشاء حديقة الحيوان لتخزين eleventzoo zoo = new zoo () ؛ eleventsystem.out.println ("أضاف حيوانًا جديدًا باسم" + animal.getName () + "'") ؛}) ؛ // إضافة حيوان يخطر المستمع المسجل.وبالمثل ، يمكن أيضًا استخدام وظائف Lambda لإكمال مثل هذه المهام:
الفئة العامة الرئيسية {public static void main (string [] args) {// إنشاء حديقة الحيوان لتخزين leatszoo zoo = new zoo () ؛ // تسجيل المستمعين ليتم إخطاره عند إضافة حيوان leadersozoo.addanimal (حيوان جديد ("نمر")) ؛}}تجدر الإشارة إلى أن وظيفة Lambda مناسبة فقط للمواقف التي توجد فيها وظيفة واحدة فقط في واجهة المستمع. على الرغم من أن هذا المطلب يبدو صارمًا ، إلا أن العديد من المستمعين هم في الواقع وظائف واحدة ، مثل animaladdedlistener في المثال. إذا كانت الواجهة تحتوي على وظائف متعددة ، فيمكنك اختيار استخدام فئات داخلية مجهولة.
هناك مشكلة في التسجيل الضمني للمستمع الذي تم إنشاؤه: نظرًا لأن الكائن يتم إنشاؤه في نطاق مكالمة التسجيل ، فمن المستحيل تخزين إشارة إلى مستمع معين. هذا يعني أنه لا يمكن إلغاء المستمعين المسجلين من خلال وظائف Lambda أو الفئات الداخلية المجهولة لأن وظائف الإلغاء تتطلب إشارة إلى المستمع المسجل. تتمثل إحدى الطرق السهلة لحل هذه المشكلة في إرجاع إشارة إلى المستمع المسجل في وظيفة RecordAnimalAddedListener. وبهذه الطريقة ، يمكنك إلغاء تسجيل المستمع الذي تم إنشاؤه باستخدام وظائف Lambda أو فئات داخلية مجهولة. رمز الطريقة المحسّن هو كما يلي:
PublicAdaddedListener registractanimaladdedListener (AnimalAddedListener Bearner) {// إضافة المستمع إلى قائمة المستمعين المسجلين. مستمع إرجاع ؛}رمز العميل لتفاعل الوظيفة المعاد تصميمه هو كما يلي:
الفئة العامة الرئيسية {public static void main (string [] args) {// إنشاء حديقة الحيوان لتخزين eleventzoo zoo = new zoo () ؛ "" ")) ؛ // إضافة حيوان يخطر المستمع المسجل. Addanimal (حيوان جديد (" Tiger ")) ؛تتم إضافة ناتج النتيجة في هذا الوقت فقط حيوان جديد يحمل اسم "Tiger" ، لأنه تم إلغاء المستمع قبل إضافة الحيوان الثاني:
أضاف حيوان جديد يحمل اسم "النمر"
إذا تم اعتماد حل أكثر تعقيدًا ، فيمكن أن تقوم وظيفة التسجيل أيضًا بإرجاع فئة المتلقي بحيث يتم استدعاء مستمع UNGISTER ، على سبيل المثال:
public class animaladdedlistenerreceipt {private finaladdedistener beasherer ؛ publicaddededListenerReceipt (AnimalAddedListener beasherer) {this.listener = leader ؛} public animaladdedlistener getListener () {return this.listener ؛}}}}}سيتم استخدام الاستلام كقيمة الإرجاع لوظيفة التسجيل ويتم إلغاء معلمات الإدخال لوظيفة التسجيل. في هذا الوقت ، يكون تطبيق حديقة الحيوان كما يلي:
الطبقة العامة ZooUsingReceipt {// ... السمات القائمة والمُنشئ ... publicAddedDedListenerCeipt registractanimaladdedListener (AnimalAddedListener beasherer) {// إضافة المستمع إلى قائمة المستمعين المسجلين (animaladdedlistenerreceipt refext) {// قم بإزالة المستمع من قائمة المستمعين المسجلين.تتيح آلية التنفيذ المستقبلة الموضحة أعلاه تخزين المعلومات للاتصال بالمستمع عند الإلغاء ، أي إذا كانت خوارزمية تسجيل الإلغاء تعتمد على حالة المستمع عندما يسجل الموضوع المستمع ، فسيتم حفظ هذه الحالة. إذا كان تسجيل الإلغاء يتطلب فقط إشارة إلى المستمع المسجل السابق ، فستظهر تقنية الاستقبال مزعجة ولا ينصح بها.
بالإضافة إلى المستمعين المعقدين بشكل خاص ، فإن الطريقة الأكثر شيوعًا لتسجيل المستمعين هي من خلال وظائف Lambda أو من خلال فصول داخلية مجهولة المصدر. بالطبع ، هناك استثناءات ، أي الفئة التي تحتوي على موضوع ينفذ واجهة المراقب ويسجل مستمعًا يدعو إلى الهدف المرجعي. الحالة كما هو موضح في الكود التالي:
تنفذ ZooContainer من الفئة العامة animaladdedistener {private zoo zoo = new zoo () ؛ public zooocontainer () {// سجل هذا الكائن كمستمع. {system.out.println ("Andival Addunt with" " + Animal.getName () +" '") ؛} الفراغ العام الثابت الرئيسي (سلسلة [] args) {// إنشاء zoo containerzoocontainer zoocontainer = new zoocontainer () ؛ حيوان ("نمر")) ؛}}هذا النهج مناسب فقط للحالات البسيطة ولا يبدو الرمز محترفًا بدرجة كافية ، ولا يزال يحظى بشعبية كبيرة بين مطوري Java الحديثين ، لذلك من الضروري فهم كيفية عمل هذا المثال. نظرًا لأن Zoocontainer ينفذ واجهة AnimalAddedListener ، يمكن تسجيل مثيل (أو كائن) من Zoocontainer كأحد الأطراف على animaladdedlistener. في فئة zooocontainer ، يمثل هذا المرجع مثيلًا للكائن الحالي ، أي zooocontainer ، ويمكن استخدامه كمحرك animaladdedlistener.
بشكل عام ، لا يلزم جميع فئات الحاويات لتنفيذ هذه الوظائف ، وفئة الحاوية التي تنفذ واجهة المستمع يمكنها فقط استدعاء وظيفة تسجيل الموضوع ، ولكن ببساطة تمرير المرجع إلى وظيفة السجل ككائن المستمع. في الفصول التالية ، سيتم تقديم الأسئلة الشائعة والحلول للبيئات المتعددة.
يوفر لك ONEEPM حلول أداء تطبيق Java من طرف إلى طرف. نحن ندعم جميع أطر عمل Java الشائعة وخوادم التطبيق لمساعدتك في اكتشاف اختناقات النظام بسرعة وتحديد الأسباب الجذرية للتشوهات. النشر على مستويات الدقيقة والخبرة على الفور ، لم تكن مراقبة Java أسهل. لقراءة المزيد من المقالات التقنية ، يرجى زيارة مدونة ONEAPM للتكنولوجيا الرسمية.
يقدم المحتوى أعلاه المحتوى ذي الصلة لاستخدام Java 8 لتنفيذ وضع المراقب (الجزء 1). تقدم المقالة التالية طريقة استخدام Java 8 لتنفيذ وضع المراقب (الجزء 2). سيستمر الأصدقاء المهتمين في التعلم ، على أمل أن يكون مفيدًا للجميع!