في المقالة السابقة ، قدمت طريقة استخدام Java8 لتنفيذ نمط المراقب (الجزء 1). تستمر هذه المقالة في تقديم المعرفة ذات الصلة بنمط المراقب Java8. المحتوى المحدد هو كما يلي:
تنفيذ آمن الموضوع
يقدم الفصل السابق تنفيذ نمط المراقب في بيئة Java الحديثة. على الرغم من أنها بسيطة ولكنها كاملة ، فإن هذا التنفيذ يتجاهل مشكلة رئيسية: سلامة مؤشر الترابط. معظم تطبيقات Java مفتوحة متعددة الخيوط ، ويستخدم وضع المراقب في الغالب في أنظمة متعددة الخيوط أو غير متزامنة. على سبيل المثال ، إذا قامت خدمة خارجية بتحديث قاعدة البيانات الخاصة بها ، فسيتلقى التطبيق أيضًا رسالة غير متزامنة ثم إخطار المكون الداخلي بالتحديث في وضع المراقب ، بدلاً من التسجيل المباشر والاستماع إلى الخدمة الخارجية.
تركز سلامة الخيط في وضع المراقب بشكل أساسي على جسم الوضع ، لأن تعارضات مؤشرات الترابط من المحتمل أن تحدث عند تعديل مجموعة المستمع المسجل. على سبيل المثال ، يحاول مؤشر ترابط واحد إضافة مستمع جديد ، بينما يحاول مؤشر الترابط الآخر إضافة كائن حيوان جديد ، والذي يؤدي إلى الإشعارات إلى جميع المستمعين المسجلين. بالنظر إلى ترتيب التسلسل ، قد يكون أو لا يكون مؤشر الترابط الأول قد أكمل تسجيل المستمع الجديد قبل أن يتلقى المستمع المسجل إشعارًا للحيوان المضافة. هذه حالة كلاسيكية من مسابقة موارد الخيوط ، وهذه الظاهرة هي التي تخبر المطورين أنهم يحتاجون إلى آلية لضمان سلامة الخيوط.
أسهل حل لهذه المشكلة هو: يجب أن تتبع جميع العمليات التي تصل أو تعديل قائمة مستمع التسجيل آلية مزامنة Java ، مثل:
public animaladdededlistener registeranimaladdededlistener (AnimalAddedListener Beasher) {/*..وبهذه الطريقة ، في الوقت نفسه ، يمكن لخيط واحد فقط تعديل أو الوصول إلى قائمة المستمع المسجلة ، والتي يمكن أن تجنب بنجاح مشكلات المنافسة في الموارد ، ولكن تنشأ مشكلات جديدة ، وتكون هذه القيود صارمة للغاية (لمزيد من المعلومات حول الكلمات الرئيسية المتزامنة ونماذج التزامن Java ، يرجى الرجوع إلى صفحة الويب الرسمية). من خلال مزامنة الطريقة ، يمكن ملاحظة الوصول المتزامن إلى قائمة المستمع في جميع الأوقات. إن تسجيل وإلغاء المستمع هو عملية كتابة لقائمة المستمع ، مع إخطار المستمع للوصول إلى قائمة المستمع هو عملية للقراءة فقط. نظرًا لأن الوصول من خلال الإخطار هو عملية قراءة ، يمكن تنفيذ عمليات الإخطار المتعددة في وقت واحد.
لذلك ، طالما لا يوجد تسجيل أو إلغاء المستمع ، طالما لم يتم تسجيل التسجيل ، طالما أنه يمكن تنفيذ أي عدد من الإخطارات المتزامنة في وقت واحد دون تشغيل مسابقة للموارد على قائمة المستمع المسجلة. بالطبع ، كانت المنافسة في الموارد في المواقف الأخرى موجودة لفترة طويلة. من أجل حل هذه المشكلة ، تم تصميم قفل الموارد لـ ReadWritelock لإدارة عمليات القراءة والكتابة بشكل منفصل. رمز تنفيذ مؤشرات ترابط مؤشرات الترابط المأمّن من فئة حديقة الحيوان على النحو التالي:
الفئة العامة threadsafezoo {private final readwritelock readWritelock = new reentrantreadwritelock () ؛ محمي القفل النهائي readlock = readWritelock.readlock () ؛ محمي القفل النهائي المحمي Oritelock = readWritelock.Writelock () ؛ قائمة خاصة <imaluats> الحيوانات = جديدة arraylist <> () ؛ قائمة خاصة <AntamentDedListener> المستمعين = new ArrayList <> () المستمعين. NotifyAnimaladdedListeners (Animal) ؛} publicAddedListener registerAnimalAdedListener (AnimalAddedListener Beasherer) {// قفل قائمة المستمعين لكتابة this.writelock.lock () ؛ جرب {// إضافة المستمع إلى قائمة المستمعين المسجلين. lockthis.writelock.unlock () ؛} مستمع الإرجاع ؛} public void unregisteranimaladdedlistener (AnimalAddedListener beasherer) {// lock the list the bister this.writelock () ؛ try {// remove the beasher من قائمة الاستماع المسجلة. lockthis.writelock.unlock () ؛}} public void notifyanimaladdedisteners (Animal Animal) {// قفل قائمة المستمعين لـ readthis.readlock.lock () ؛ جرب {// explate inly inister at stefy) ؛ فتح القارئ lockthis.readlock.unlock () ؛}}}من خلال مثل هذا النشر ، يمكن أن يضمن تنفيذ الموضوع سلامة مؤشرات الترابط ويمكن أن يصدر مؤشرات الترابط المتعددة الإخطارات في نفس الوقت. ولكن على الرغم من ذلك ، لا تزال هناك مشكلتان في مسابقة الموارد لا يمكن تجاهلهما:
الوصول المتزامن إلى كل مستمع. يمكن لخيوط متعددة إخطار المستمع بأن هناك حاجة إلى حيوانات جديدة ، مما يعني أنه قد يتم استدعاء المستمع بواسطة مؤشرات ترابط متعددة في نفس الوقت.
الوصول المتزامن إلى قائمة الحيوانات. قد تضيف مؤشرات ترابط متعددة كائنات إلى قائمة الحيوانات في نفس الوقت. إذا كان لترتيب الإشعارات تأثير ، فقد يؤدي ذلك إلى منافسة الموارد ، مما يتطلب آلية معالجة التشغيل المتزامنة لتجنب هذه المشكلة. إذا تلقيت قائمة المستمع المسجل إشعارًا لإضافة Animal2 ثم تتلقى إشعارًا لإضافة Animal1 ، فسيحدث مسابقة الموارد. ومع ذلك ، إذا تم تنفيذ إضافة Animal1 و Animal2 بواسطة خيوط مختلفة ، فمن الممكن أيضًا إكمال إضافة Animal1 قبل Animal2. على وجه التحديد ، يضيف الموضوع 1 Animal1 قبل إخطار المستمع ويغلق الوحدة النمطية ، ويضيف الموضوع 2 Animal2 ويبلغ المستمع ، ثم يخطر الموضوع 1 المستمع الذي تمت إضافته على Animal1. على الرغم من أنه يمكن تجاهل منافسة الموارد عندما لا يتم النظر في ترتيب التسلسل ، إلا أن المشكلة حقيقية.
الوصول المتزامن إلى المستمعين
يمكن تنفيذ مستمعي الوصول المتزامن عن طريق ضمان سلامة مؤشر ترابط المستمعين. التمسك بروح "المسؤولية الذاتية" للفئة ، فإن المستمع لديه "الالتزام" لضمان سلامة الخيط الخاصة به. على سبيل المثال ، بالنسبة للمستمع الذي تم حسابه أعلاه ، قد يؤدي زيادة أو تقليل أعداد الحيوانات بواسطة مؤشرات ترابط متعددة إلى مشاكل سلامة الخيط. لتجنب هذه المشكلة ، يجب أن يكون حساب الأرقام الحيوانية العمليات الذرية (المتغيرات الذرية أو مزامنة الطريقة). رمز الحل المحدد هو كما يلي:
public threadsafeCountingAnimalAdedDedListener تنفذ animaladdedlistener {private static atomiclong eleuctionAddedCount = new Atomiclong (0) ؛@Outridepublic void updateanimaladded (Animal Animal) {// زيادة عدد الحيوانات.رمز حل تزامن الطريقة كما يلي:
الطبقة العامة countinganimaladdedlistener تنفذ animaladdededlistener {private static int eleventsaddedcount = 0 ؛ Overridepublic Synchronized void updateanimaladdddded (حيوان حيوان) {// زيادة عدد الحيواناتيجب التأكيد على أن المستمع يجب أن يضمن سلامة الخيط الخاصة به. يحتاج الموضوع إلى فهم المنطق الداخلي للمستمع ، بدلاً من مجرد ضمان سلامة مؤشرات الترابط للوصول إلى المستمع وتعديله. خلاف ذلك ، إذا شارك العديد من الموضوعات نفس المستمع ، فيجب على كل فئة موضوع إعادة كتابة رمز آمن مؤشر الترابط. من الواضح أن هذا الرمز ليس موجزًا بما فيه الكفاية ، لذلك يجب تنفيذ آمن مؤشرات الترابط في فئة المستمع.
الإخطارات المطلوبة للمستمعين
عندما يُطلب من المستمع تنفيذها بطريقة منظمة ، لا يمكن لقفل القراءة والكتابة تلبية الاحتياجات ، ويجب تقديم آلية جديدة للتأكد من أن ترتيب استدعاء وظيفة الإخطار يتسق مع الترتيب الذي تتم فيه إضافة الحيوان إلى حديقة الحيوان. حاول بعض الأشخاص تنفيذها باستخدام مزامنة الطريقة ، ولكن وفقًا لإدخال تزامن الطريقة في وثائق Oracle ، يمكن ملاحظة أن تزامن الطريقة لا يوفر إدارة ترتيب تنفيذ التشغيل. إنه يضمن فقط عدم توقف العمليات الذرية ، ولا تضمن ترتيب مؤشر ترابط التنفيذ الأول الأول (FIFO). يمكن لـ REENTRANTREADWRITELOCK تنفيذ أمر التنفيذ هذا ، والرمز كما يلي:
الطبقة العامة orderThReadSafezoo {private final readWritelock readWritelock = جديد reentrantreadwritelock (true) ؛ محمي القفل النهائي readlock = readWritelock.readlock () ؛ محمي القفل النهائي المحمي Oritelock = readWritelock.Writelock () ؛ قائمة خاصة <imaluats> الحيوانات = جديدة arraylist <> () ؛ قائمة خاصة <AntamentDedListener> المستمعين = new ArrayList <> () المستمعين. NotifyAnimaladdedListeners (Animal) ؛} publicAddedListener registerAnimalAdedListener (AnimalAddedListener Beasherer) {// قفل قائمة المستمعين لكتابة this.writelock.lock () ؛ جرب {// إضافة المستمع إلى قائمة المستمعين المسجلين. lockthis.writelock.unlock () ؛} مستمع الإرجاع ؛} public void unregisteranimaladdedlistener (AnimalAddedListener beasherer) {// lock the list the bister this.writelock () ؛ try {// remove the beasher من قائمة الاستماع المسجلة. lockthis.writelock.unlock () ؛}} public void notifyanimaladdedisteners (Animal Animal) {// قفل قائمة المستمعين لـ readthis.readlock.lock () ؛ جرب {// explate inly inister at stefy) ؛ فتح القارئ lockthis.readlock.unlock () ؛}}}وبهذه الطريقة ، ستحصل على أذونات القراءة والكتابة على أذونات القراءة والكتابة بترتيب الأول في الأول (FIFO). على سبيل المثال ، يسجل الموضوع 1 مستمعًا ، يحاول الموضوع 2 إخطار المستمع المسجل بعد بدء عملية التسجيل ، ويحاول الموضوع 3 إخطار المستمع المسجل عندما ينتظر الموضوع 2 قفل القراءة فقط ، واعتماد طريقة الترتيب العادل ، ويكمل الموضوع 1 عملية التسجيل أولاً ، ثم يخطر الموضوع 2 المستمع ، وأخيراً الموضوع 3 لا يوجد مستمع. هذا يضمن أن يكون أمر التنفيذ وترتيب بدء العمل متسقًا.
إذا تم اعتماد مزامنة الطريقة ، على الرغم من أن الخيط 2 يتصدر أولاً احتلال الموارد ، فقد لا يزال الموضوع 3 يحصل على قفل المورد قبل الموضوع 2 ، ولا يمكن ضمان أن يخطر الموضوع 2 المستمع أولاً من الموضوع 3. مفتاح المشكلة هو: يمكن أن تتضمن طريقة الترتيب العادل تنفيذ مؤشرات الترابط بالترتيب بالموارد. آلية الترتيب للقراءة والكتابة أقفال معقدة للغاية. يجب أن تشير إلى الوثائق الرسمية لـ ReentranTreadWritelock للتأكد من أن منطق القفل يكفي لحل المشكلة.
تم تنفيذ سلامة الخيط حتى الآن ، وسيتم تقديم مزايا وعيوب استخراج منطق الموضوع وتغليف فئة Mixin الخاصة به في وحدات رمز قابلة للتكرار في الفصول التالية.
منطق السمة مغلفة بفئة Mixin
إنه أمر جذاب للغاية لتغليف تطبيق تصميم نمط المراقب المذكور أعلاه في فئة Mixin المستهدفة. بشكل عام ، يحتوي المراقبون في وضع المراقب على مجموعة من المستمعين المسجلين ؛ تسجيل الوظائف المسؤولة عن تسجيل مستمعين جدد ؛ وظائف UNGISTER المسؤولة عن إلغاء وظائف UNGISTER المسجلة وإخطار الوظائف المسؤولة عن إخطار المستمعين. بالنسبة للمثال أعلاه لحديقة الحيوان ، فإن جميع العمليات الأخرى لفئة حديقة الحيوان باستثناء أن قائمة الحيوانات مطلوبة للمشكلة هي تنفيذ منطق الموضوع.
ويرد أدناه حالة فئة Mixin. تجدر الإشارة إلى أنه من أجل جعل الرمز أكثر إيجازًا ، تتم إزالة الكود حول سلامة مؤشرات الترابط هنا:
Public Abstract Class ObservablesUbjectMixin <SnaleerType> {List Private List <SnaleerType> المستمعين = جديد ArrayList <> () ؛ المستمع العام registerlister (مستمع المستمع) {// أضف المستمع إلى قائمة المستمعين المسجلين. {// أزل المستمع من قائمة المستمعين المسجلين.نظرًا لعدم توفير معلومات الواجهة الخاصة بنوع المستمع المسجل ، لا يمكن إخطار مستمع معين مباشرة ، لذلك من الضروري التأكد من أن عالمية وظيفة الإخطار والسماح للعميل بإضافة بعض الوظائف ، مثل قبول مطابقة المعلمات لأنواع المعلمات العامة لتكون قابلة للتطبيق على كل مستمع. رمز التنفيذ المحدد كما يلي:
يمتد ZooUsingMixin من الطبقة العامة على مراقبة absondablesUbjectMixin <InmalAdDedListener> {قائمة خاصة <imalant> الحيوانات = new ArrayList <> () المستمع. updateanimaladded (حيوان)) ؛}}تتمثل أكبر ميزة في تقنية فئة Mixin في تغليف موضوع المراقب النمطي في فئة قابلة للتكرار ، بدلاً من تكرار المنطق في كل فئة موضوع. بالإضافة إلى ذلك ، تجعل هذه الطريقة تنفيذ فئة حديقة الحيوان أبسط ، وتخزين معلومات الحيوانات فقط دون النظر في كيفية تخزين المستمعين وإخطارهم.
ومع ذلك ، فإن استخدام فئات Mixin ليس مجرد ميزة. على سبيل المثال ، ماذا لو كنت تريد تخزين أنواع متعددة من المستمعين؟ على سبيل المثال ، من الضروري أيضًا تخزين نوع المستمع AnimalRemovedListener. فئة Mixin هي فئة مجردة. لا يمكن مورث فئات مجردة متعددة في نفس الوقت في Java ، ولا يمكن تنفيذ فئة Mixin باستخدام واجهة بدلاً من ذلك. وذلك لأن الواجهة لا تحتوي على حالة ، ويجب استخدام الحالة في وضع المراقب لحفظ قائمة المستمع المسجلة.
يتمثل أحد الحلول في إنشاء نوع مستمع Zoolistener الذي سيتم إخطاره عندما تزيد الحيوانات وتناقص. الرمز يشبه هذا:
الواجهة العامة Zoolistener {public void onanimaladded (Animal Animal) ؛ public void onanimalremoved (Animal Animal) ؛}وبهذه الطريقة ، يمكنك استخدام هذه الواجهة لتنفيذ مراقبة التغييرات المختلفة في حالة حديقة الحيوان باستخدام نوع المستمع:
يمتد ZooUsingMixin من الطبقة العامة على مراقبة absondablesUbjectMixin <Soolistener> {قائمة خاصة <imanation> الحيوانات = new ArrayList <> () المستمع.إن الجمع بين أنواع المستمعين المتعددة في واجهة مستمع واحدة يحل المشكلة المذكورة أعلاه ، ولكن لا تزال هناك أوجه قصور ، والتي ستتم مناقشتها بالتفصيل في الفصول التالية.
مستمع ومحول متعدد الأساليب
في الطريقة أعلاه ، إذا كانت واجهة المستمع تنفذ الكثير من الوظائف ، فستكون الواجهة مطوّلة للغاية. على سبيل المثال ، يحتوي Swing Mouselistener على 5 وظائف ضرورية. على الرغم من أنك قد تستخدم واحدة منها فقط ، يجب عليك إضافة هذه الوظائف الخمس طالما أنك تستخدم حدث النقر بالماوس. أكثر عرضة لاستخدام أجسام الوظائف الفارغة لتنفيذ الوظائف المتبقية ، والتي ستجلب بلا شك ارتباكًا غير ضروري للرمز.
أحد الحلول هو إنشاء محول (يأتي المفهوم من نمط المحول الذي اقترحه GOF). يتم تنفيذ تشغيل واجهة المستمع في شكل وظائف مجردة لميراث فئة المستمع المحددة. وبهذه الطريقة ، يمكن لفئة المستمع المحددة تحديد الوظائف التي يحتاجها واستخدام العمليات الافتراضية للوظائف التي لا يلزمها المحول. على سبيل المثال ، في فئة Zoolistener في المثال أعلاه ، قم بإنشاء ZooaDapter (قواعد التسمية للمحول متسقة مع المستمع ، تحتاج فقط إلى تغيير المستمع في اسم الفصل إلى المحول) ، كما يلي:
تنفذ Zooadapter من الطبقة العامة Zoolistener {Overridepublic void onanimaladded (Animal Animal) {} Overridepublic void onanimalremoved (Animal Animal) {}}للوهلة الأولى ، تعتبر فئة المحول هذه غير مهمة ، لكن لا يمكن التقليل من الراحة التي يجلبها. على سبيل المثال ، بالنسبة للفئات المحددة التالية ، فقط حدد الوظائف المفيدة لهم:
الطبقة العامة nameprinterzooadapter يمتد ZooAdapter {Overridepublic void onanimaladded (Animal Animal) {// print اسم الحيوان الذي تم إضافته shestem.out.println ("Animal tame" + animal.getname ()) ؛}}}هناك بديلان يمكنهما أيضًا تنفيذ وظائف فئة المحول: الأول هو استخدام الوظيفة الافتراضية ؛ والآخر هو دمج واجهة المستمع وفئة المحول في فئة محددة. يتم اقتراح الوظيفة الافتراضية حديثًا بواسطة Java 8 ، مما يسمح للمطورين بتوفير طرق تنفيذ افتراضية (دفاع) في الواجهة.
هذا التحديث إلى مكتبة Java هو تسهيل المطورين بشكل أساسي لتنفيذ ملحقات البرنامج دون تغيير الإصدار القديم من الكود ، لذلك يجب استخدام هذه الطريقة بحذر. بعد استخدامه عدة مرات ، سيشعر بعض المطورين أن الكود المكتوب بهذه الطريقة ليس محترفًا بما فيه الكفاية ، ويعتقد بعض المطورين أن هذه هي ميزة Java 8. بغض النظر عن السبب ، فهم بحاجة إلى فهم ماهية النية الأصلية لهذه التكنولوجيا ، ثم يقررون ما إذا كان سيتم استخدامها بناءً على أسئلة محددة. رمز واجهة Zoolistener المطبق باستخدام الوظيفة الافتراضية هو كما يلي:
الواجهة العامة Zoolistener {الافتراضي public void onanimaladded (Animal Animal) {} الافتراضي الفراغ العام onanimalremoved (Animal Animal) {}}باستخدام الوظائف الافتراضية ، لا يحتاج تطبيق الفئات المحددة للواجهة إلى تنفيذ جميع الوظائف في الواجهة ، ولكن بدلاً من ذلك تنفيذ الوظائف المطلوبة بشكل انتقائي. على الرغم من أن هذا حل بسيط نسبيًا لمشكلة توسيع الواجهة ، يجب على المطورين إيلاء المزيد من الاهتمام عند استخدامه.
الحل الثاني هو تبسيط وضع المراقب ، وإلغاء واجهة المستمع ، واستخدام فئات محددة لتنفيذ وظائف المستمع. على سبيل المثال ، تصبح واجهة Zoolistener ما يلي:
الطبقة العامة Zoolistener {public void onanimaladded (Animal Animal) {} public void onanimalremoved (Animal Animal) {}}يبسط هذا الحل التسلسل الهرمي لنمط المراقب ، لكنه لا ينطبق على جميع الحالات ، لأنه إذا تم دمج واجهة المستمع في فئة معينة ، لا يمكن للمستمع المحدد تنفيذ واجهات استماع متعددة. على سبيل المثال ، إذا تم كتابة واجهات AnimalAddedListener و AnimalRemovedListener في نفس الفئة الملموسة ، فلن يتمكن مستمع واحد محدد من تنفيذ كلا الواجهات في نفس الوقت. بالإضافة إلى ذلك ، فإن نية واجهة المستمع أكثر وضوحًا من تلك الخاصة بالفئة المحددة. من الواضح أن الأول هو توفير واجهات لفصول أخرى ، لكن الأخير ليس واضحًا.
بدون الوثائق المناسبة ، لن يعلم المطور أن هناك بالفعل فئة تلعب دور الواجهة وينفذ جميع وظائفها المقابلة. بالإضافة إلى ذلك ، لا يحتوي اسم الفصل على محولات لأن الفصل لا يتناسب مع واجهة معينة ، وبالتالي فإن اسم الفصل لا يعني على وجه التحديد هذه النية. خلاصة القول ، تتطلب مشكلة محددة اختيار طريقة محددة ، ولا توجد طريقة في كل شيء.
قبل أن نبدأ الفصل التالي ، من المهم أن نذكر أن المحولات شائعة في وضع المراقبة ، وخاصة في الإصدارات الأقدم من كود Java. يتم تنفيذ API Swing بناءً على المحولات ، حيث يستخدم العديد من التطبيقات القديمة في نمط المراقب في Java 5 و Java 6. قد لا يتطلب المستمع في حالة حديقة الحيوان محولًا ، ولكنه يحتاج إلى فهم الغرض من المحول وتطبيقه ، لأنه يمكننا استخدامه في التعليمات البرمجية الموجودة. سيقدم الفصل التالي مستمعين كثافة الوقت. قد يقوم هذا النوع من المستمعين بإجراء عمليات مستهلكة للوقت أو إجراء مكالمات غير متزامنة ولا يمكنها إعطاء قيمة الإرجاع على الفور.
مستمع معقد وحظر
أحد الافتراضات حول نمط المراقب هو أنه عند تنفيذ وظيفة ، يتم استدعاء سلسلة من المستمعين ، لكن من المفترض أن هذه العملية شفافة تمامًا للمتصل. على سبيل المثال ، عندما يضيف رمز العميل Animal in Zoo ، من غير المعروف أن سلسلة من المستمعين سيتم استدعاؤهم قبل نجاح العائد. إذا استغرق تنفيذ المستمع وقتًا طويلاً (يتأثر وقته بعدد المستمعين ، ووقت تنفيذ كل مستمع) ، فإن رمز العميل سيكون على دراية بالآثار الجانبية الزمنية لهذه الزيادة البسيطة في عمليات الحيوانات.
لا يمكن لهذه المقالة مناقشة هذا الموضوع بطريقة شاملة. فيما يلي الأشياء التي يجب على المطورين الانتباه إليها عند الاتصال بالمستمعين المعقدين:
يبدأ المستمع موضوعًا جديدًا. بعد بدء تشغيل الخيط الجديد ، أثناء تنفيذ منطق المستمع في مؤشر الترابط الجديد ، يتم إرجاع نتائج المعالجة لوظيفة المستمع ويتم تشغيل المستمعين الآخرين.
يبدأ الموضوع موضوعًا جديدًا. على عكس التكرارات الخطية التقليدية لقوائم المستمع المسجلة ، تقوم وظيفة إخطار الموضوع بإعادة تشغيل مؤشر ترابط جديد ثم تكرر على قائمة المستمع في الموضوع الجديد. يتيح ذلك لوظيفة الإخطار لإخراج قيمة الإرجاع الخاصة بها أثناء إجراء عمليات المستمعين الآخرين. تجدر الإشارة إلى أن هناك حاجة إلى آلية سلامة مؤشرات الترابط للتأكد من أن قائمة المستمع لا تخضع للتعديلات المتزامنة.
استمع مستمع قائمة الانتظار ويقوم بوظائف الاستماع مع مجموعة من المواضيع. تغليف عمليات المستمع في بعض الوظائف وقائمة الانتظار بدلاً من مكالمة تكرارية بسيطة إلى قائمة المستمعين. بمجرد تخزين هؤلاء المستمعين في قائمة الانتظار ، يمكن للموضوع أن يطفو عنصرًا واحدًا من قائمة الانتظار وتنفيذ منطق الاستماع الخاص به. هذا مشابه لمشكلة المنتج والمستهلك. تنتج عملية الإخطار قائمة انتظار للوظائف القابلة للتنفيذ ، والتي تقوم بعد ذلك بإخراج قائمة الانتظار بدورها وتنفيذ هذه الوظائف. تحتاج الوظيفة إلى تخزين الوقت الذي تم إنشاؤه فيه بدلاً من الوقت الذي تم فيه تنفيذ وظيفة المستمع للاتصال. على سبيل المثال ، وظيفة تم إنشاؤها عند استدعاء المستمع ، ثم تحتاج الوظيفة إلى تخزين النقطة الزمنية. هذه الوظيفة تشبه العمليات التالية في جافا:
public animaladdedfunctor {private final animaladdedlistener bearner ؛ private final animal parameter ؛ publicaddedfunctor (AnimalAddedListener bisterer ، parmeter) {this.listener = this.parameter = parameter ؛} public void execut CreationThis.Listener.updateanimaladded (this.parameter) ؛}}يتم إنشاء الوظائف وحفظها في قائمة انتظار ويمكن استدعاؤها في أي وقت ، بحيث لا توجد حاجة لإجراء عملياتها المقابلة على الفور عند عبور قائمة قائمة القائمة. بمجرد دفع كل وظيفة تنشط المستمع إلى قائمة الانتظار ، سيعيد "مؤشر ترابط المستهلك" الحقوق التشغيلية إلى رمز العميل. سيقوم "مؤشر ترابط المستهلك" بتنفيذ هذه الوظائف في وقت ما في وقت لاحق ، تمامًا كما لو أن المستمع يتم تنشيطه بواسطة وظيفة الإخطار. تسمى هذه التقنية ربط المعلمة بلغات أخرى ، والتي تناسب المثال أعلاه فقط. يتمثل جوهر التكنولوجيا في حفظ معلمات المستمع ثم استدعاء وظيفة التنفيذ () مباشرة. إذا تلقى المستمع معلمات متعددة ، فإن طريقة المعالجة متشابهة.
تجدر الإشارة إلى أنه إذا كنت ترغب في حفظ ترتيب التنفيذ للمستمع ، فأنت بحاجة إلى تقديم آلية فرز شاملة. في المخطط 1 ، يقوم المستمع بتنشيط مؤشرات ترابط جديدة بالترتيب العادي ، مما يضمن تنفيذ المستمع بترتيب التسجيل. في المخطط 2 ، تدعم قوائم الانتظار الفرز ، وسيتم تنفيذ الوظائف الموجودة فيها بالترتيب الذي يدخلون في قائمة الانتظار. ببساطة ، يحتاج المطورون إلى الانتباه إلى تعقيد تنفيذ المستمعين متعدد الخيوط والتعامل معه بعناية لضمان تنفيذ الوظائف المطلوبة.
خاتمة
قبل كتابة نموذج Observer في الكتاب في عام 1994 ، كان بالفعل نموذجًا رئيسيًا لتصميم البرمجيات ، حيث يوفر العديد من الحلول المرضية للمشاكل التي غالباً ما تنشأ في تصميم البرمجيات. لطالما كانت Java رائدة في استخدام هذا النمط وتغلف هذا النمط في مكتبته القياسية ، ولكن نظرًا لأن Java قد تم تحديثه إلى الإصدار 8 ، فمن الضروري جدًا إعادة فحص استخدام الأنماط الكلاسيكية فيه. مع ظهور تعبيرات Lambda وغيرها من الهياكل الجديدة ، اتخذ هذا النمط "القديم" حيوية جديدة. سواء أكانت تتعامل مع البرامج القديمة أو باستخدام هذه الطريقة الطويلة الأمد لحل المشكلات الجديدة ، خاصة بالنسبة لمطوري Java ذوي الخبرة ، فإن نمط المراقب هو الأداة الرئيسية للمطورين.
يوفر لك ONEEPM حلول أداء تطبيق Java من طرف إلى طرف. نحن ندعم جميع أطر عمل Java الشائعة وخوادم التطبيق لمساعدتك في اكتشاف اختناقات النظام بسرعة وتحديد الأسباب الجذرية للتشوهات. النشر على مستويات الدقيقة والخبرة على الفور ، لم تكن مراقبة Java أسهل. لقراءة المزيد من المقالات التقنية ، يرجى زيارة مدونة ONEAPM للتكنولوجيا الرسمية.
يقدم لك المحتوى أعلاه كيفية استخدام Java8 لتنفيذ وضع المراقب (الجزء 2) ، وآمل أن يكون مفيدًا للجميع!