1. تعريف وضع المراقب:
يسمى وضع المراقب أيضًا وضع نشر الاشتراك ، حيث يدير كائن مستهدف جميع كائنات المراقب التي تعتمد عليه ويصدر الإخطارات بنشاط عند تغيير حالته. عادة ما يتم تحقيق ذلك عن طريق استدعاء أساليب كل مراقب. يستخدم هذا النمط عادة في أنظمة معالجة الأحداث.
1. الهيكل العام لنمط المراقب
أولاً ، دعنا نلقي نظرة على وصف مخطط الفصل لنمط المراقب:
أدوار وضع المراقب هي كما يلي:
الموضوع (واجهة موضوع الملخص): يحدد سلسلة من العمليات في قائمة المراقب في فئة السمة ، بما في ذلك الإضافة ، الحذف ، الإخطار ، إلخ.
موضوع ملموس (فئة موضوع محددة):
Observer (واجهة مراقب مجردة): يحدد المراقب لقبول العمليات في حالة تحديث فئة الموضوع.
ConcreteObserver (فئة مراقب محددة): ينفذ منطق مثل تحديث إخطارات فئة الموضوع بواسطة واجهة المراقب.
من هذا الرسم البياني للفصل ، يمكننا أن نرى أن فئة السمة تحافظ على قائمة فئة تنفذ واجهة المراقب. يستخدم فئة السمة هذه القائمة لأداء سلسلة من الإضافات والحذف والتعديلات على المراقب. يمكن لفئة Observer أيضًا استدعاء طريقة التحديث بنشاط لفهم معلومات تحديث الحالة لفئة السمة.
تصف المخططات الفئة المذكورة أعلاه فقط فكرة نمط المراقب الأساسية ، وهناك العديد من أوجه القصور. على سبيل المثال ، بصفتك مراقبًا ، يمكنك أيضًا الاشتراك بنشاط في مواضيع معينة ، وما إلى ذلك. الأمثلة التالية ستجري بعض التغييرات لتطبيق منطق أعمال محدد.
2. مثال وضع المراقب
نقوم ببناء مراقب ومواضيع ، حيث يمكن للمراقبين الاشتراك بنشاط في الموضوعات أو إلغاؤها. تتم إدارة فئة الموضوع بشكل موحد من قبل مدير الموضوع. ما يلي هو مخطط الفصل:
موضوع:
موضوع الواجهة العامة {// تسجيل سجل مراقب باطل عام (Observer Observer) ؛ // إزالة مراقب الفراغ العام إزالة (المراقب المراقب) ؛ // إخطار جميع المراقبين public void notifyobservers () ؛ // احصل على الرسالة التي سيتم نشرها بواسطة سلسلة Topic Class Public GetMessage () ؛} CbressesUbject: Public Class MySubject تنفذ الموضوع {private list <Seberver> المراقبين ؛ تغيرت منطقية خاصة. رسالة سلسلة خاصة ؛ // قفل الكائن ، المستخدم لتحديث متزامن قائمة المراقب الخاص بكائن نهائي خاص = كائن جديد () ؛ public mysubject () {jostervers = new ArrayList <Seberver> () ؛ تغير = خطأ ؛ } Override Public Void Register (Observer Observer) {if (observer == null) رمي nullpointerxception () ؛ // شهادة عدم التكرار إذا (! المراقبين. } override public void remove (observer observer) {postervers.remove (observer) ؛ } Override public void notifyObservers () {// temp list <soberver> tempobservers = null ؛ Synchronized (mutex) {if (! change) return ؛ tempobservers = new ArrayList <> (this.Observers) ؛ this.Changed = false ؛ } لـ (observer obj: tempobservers) {obj.update () ؛ }} // الفئة السمة تنشر رسالة جديدة public void makechanged (رسالة سلسلة) {system.out.println ("الموضوع يجعل التغيير:" + رسالة) ؛ this.message = رسالة ؛ this.Changed = true ؛ eletiplesoBservers () ؛ } Override public string getMessage () {return this.message ؛ }}عندما يقوم CorperSubject بإجراء تحديث ، يتم إخطار جميع المراقبين في القائمة ، ويتم استدعاء طريقة تحديث المراقب لتنفيذ المنطق بعد تلقي الإخطار. لاحظ كتلة التزامن في الإخطار هنا. في حالة متعدد الخيوط ، من أجل تجنب إضافة وحذف قائمة المراقب بواسطة مؤشرات الترابط الأخرى عند نشر الإخطارات في فئة الموضوع ، يتم استخدام قائمة مؤقتة في كتلة التزامن للحصول على قائمة المراقب الحالية.
الموضوع: مدير فئة الموضوع
موضوع الفئة العامة {// اسم السجل - خريطة الخريطة الخاصة <string ، موضوع> موضوع = new hashmap <string ، thision> () ؛ void public addSubject (اسم السلسلة ، الموضوع) {thisionList.put (الاسم ، الموضوع) ؛ } public void addSubject (موضوع) {thisionList.put (thision.getClass (). getName () ، الموضوع) ؛ } الموضوع العام getUbject (سلسلة موضوع) {return thisplist.get (thisionName) ؛ } void public removesUbject (اسم السلسلة ، الموضوع) {} void public removesUbject (موضوع موضوع) {} // singleton private substmanagement () {} public static static getInstance () {return thinksmaniceInstance.instance ؛ } private static class characterManagementInstance {static final thinkMancing مثيل = new thinkingManagement () ؛ }}الغرض من مدير الموضوع هو الحصول على كائن مثيل للموضوع عندما يشترك المراقب في موضوع ما.
المراقب:
الواجهة العامة Observer {public void update () ؛ setSubject public void (موضوع الموضوع) ؛} QuortteObserver: Public Class Myobserver تنفذ Observer {موضوع خاص ؛ // احصل على رسالة إخطار من upistrate Override public void update () {String message = thision.getMessage () ؛ System.out.println ("من الموضوع" + موضوع. getClass (). getName () + "رسالة:" + رسالة) ؛ } Override public void setSUBject (موضوع) {this.subject = object ؛ }. }. }} الاختبار: نحن ملخصون فصول ومراقبين في كتاب وقراء
الطبقة العامة مراقبة {private static mysubject writer ؛ BEForeClass public static void setupBebeForeClass () يلقي استثناء {writer = new MySubject () ؛ // أضف كاتبًا يدعى Linus thisplicagement.getInstance (). AddSubject ("Linus" ، كاتب) ؛ } test public void test () {// تحديد العديد من القراء myobserver reader1 = new myobserver () ؛ myobserver reader2 = new myobserver () ؛ myobserver reader3 = new myobserver () ؛ reader1.SetSubject (كاتب) ؛ reader2.SetSubject (كاتب) ؛ reader3.SetSubject (كاتب) ؛ reader1.subscribe ("Linus") ؛ reader2.subscribe ("Linus") ؛ reader3.subscribe ("Linus") ؛ الكاتب. makechanged ("لدي تغيير جديد") ؛ reader1.update () ؛ }}ما سبق هو مثال صغير لنمط المراقب. يمكن ملاحظة أن كل فئة موضوع يجب أن تحتفظ بقائمة مراقب مقابلة. هنا ، يمكننا مزيد من التجريد بناءً على المستوى التجريدي للموضوع المحدد ، وضع هذا التجمع في فصل مجردة للحفاظ على قائمة مشتركة. بالطبع ، تعتمد العملية المحددة على منطق العمل الفعلي.
2. مستمع في servlet
دعنا نتحدث عن المستمع في Servlet ، دعنا نتحدث عن شكل آخر من نمط المراقب - النموذج الذي يحركه الحدث. مثل دور موضوع نمط المراقب المذكور أعلاه ، يتضمن النموذج القائم على الحدث مصادر الأحداث والأحداث المحددة والمستمعين والمستمعين المحددين.
المستمع في Servlet هو نموذج نموذجي يحركه الحدث.
هناك مجموعة من الفصول التي تعتمد على الحدث في JDK ، بما في ذلك واجهة مستمع موحدة ومصدر حدث موحد. رمز المصدر كما يلي:
/*** واجهة وضع العلامات التي يجب أن تمتد جميع واجهات مستمع الحدث. * since jdk1.1 */واجهة عامة EventListener {}هذه واجهة علامة ، وينص JDK على أن جميع المستمعين يجب أن يرثوا هذه الواجهة.
eventoBject public eventObject تنفذ java.io.serializable {private Static Final Long SerialVersionuid = 5516075349620653480L ؛ /*** الكائن الذي حدث في البداية. */ مصدر كائن عابر محمي ؛ /*** يبني حدث النموذج الأولي. * * param مصدر الكائن الذي حدث في البداية. * exception alfictalargumentException إذا كان المصدر فارغًا. */ public eventObject (مصدر الكائن) {if (source == null) رمي جديد alfictalargumentException ("مصدر فارغ") ؛ this.Source = Source ؛ } /*** الكائن الذي حدث في البداية. * * العودة للكائن الذي حدث في البداية. */ الكائن العام getSource () {return source ؛ } /*** إرجاع تمثيل سلسلة لهذا الحدث. * * @RETURN تم تمثيل سلسلة لهذا الحدث. */ public string toString () {return getClass (). getName () + "[source =" + source + "]" ؛ }}EvenObject هو مصدر حدث موحد يحدده JDK. تحدد فئة EvenObject مصدر الحدث وطريقة الحصول على مصدر الحدث.
دعنا نحلل عملية تشغيل مستمع Servlet.
1. تكوين مستمع Servlet
حاليًا ، هناك 6 أنواع من واجهات المستمع لنوعين من الأحداث في servlets ، كما هو موضح في الشكل أدناه:
وضع الزناد المحدد هو كما يلي:
2. مستمع محدد يثير عملية تشغيل
دعنا نأخذ servletRequestAtTerbultElistener كمثال لتحليل العملية التي تعتمد على الحدث هنا.
بادئ ذي بدء ، عندما يستدعي httpservletrequest طريقة setattrilbute ، يطلق عليه بالفعل org.apache.catalina.connector.request#setattrilbute طريقة. لنلقي نظرة على رمز المصدر الخاص به:
public void setAttribute (اسم السلسلة ، قيمة الكائن) {... // تم حذف رمز المنطق أعلاه // هنا المستمع هو NotifyAttributeAsigned (الاسم ، القيمة ، OldValue) ؛ }فيما يلي رمز المصدر لـ NotifyAttributeAsissigned (اسم السلسلة ، قيمة الكائن ، الكائن OldValue)
private void notifyattributeAsissigned (اسم السلسلة ، قيمة الكائن ، الكائن القديم) {// احصل على كائن مثيل للمستمع المحدد في webapp من مستمعي كائن الحاوية [] = context.getApplicationEventListeners () ؛ if ((المستمعين == null) || (المستمعين. length == 0)) {return ؛ } boolean استبدال = (oldvalue! = null) ؛ // إنشاء كائن الحدث ذي الصلة servletRequestAtTributeevent حدث = null ؛ if (استبدال) {event = new ServleTRequestAtTributeVent (context.getServletContext () ، getRequest () ، name ، oldvalue) ؛ } else {event = new ServleTRequestAtTributEvent (context.getServletContext () ، getRequest () ، name ، value) ؛ }. } // استدعاء طريقة المستمع لتنفيذ مستمع ServleTRequestAttributEner المستمع = (servleTRequestAtattributeListener) [i] ؛ جرب {if (استبدال) {leader.attributeRedPlace (event) ؛ } آخر {leader.attributeadded (event) ؛ }} catch (throwable t) {inspectUtils.HandLethRowable (t) ؛ context.getLogger (). خطأ (sm.getString ("coyoterequest.attributevent") ، t) ؛ // سوف يختار صمام الخطأ هذا الاستثناء وعرضه على سمات المستخدم. }}}يوضح المثال أعلاه بوضوح كيف يتم استدعاء ServleTRequestAttRibtListener. يحتاج المستخدمون فقط إلى تنفيذ واجهة المستمع. يغطي المستمعون في Servlets تقريبًا الأحداث التي تهتم بها طوال دورة حياة Servlet بأكملها. يمكن للاستخدام المرن لهؤلاء المستمعين أن يجعل البرنامج أكثر مرونة.
3. أمثلة شاملة
على سبيل المثال ، إذا كنت قد شاهدت أفلام شرطة TVB وعصابات TVB ، فستعرف كيف تعمل السرية. بشكل عام ، قد يكون لدى شرطي العديد من الوكلاء السريين الذين يتسللون إلى العدو ويستفسرون عن المعلومات. يعمل العميل السري بالكامل على تعليمات زعيمه. يقول القائد ما الإجراء الذي يجب أن يتبعه. إذا تغير وقت الإجراء ، فيجب عليه تغيير الوقت الذي يتعاون فيه على الفور مع الإجراء. إذا أرسل القائد الوكلاء السريين لغزو العدو ، فإن القائد يعادل موضوعًا مجردًا. أرسل المفتش تشانغ سان اثنين من الوكلاء السريين لي سي ووان وانغ وو. تعتبر Zhang San مكافئة لموضوع محدد ، ويعادل العامل السفلي مراقبًا مجردًا. هذان الوكلاء السريانان هما Li Si و Wang Wu ، وهما مراقبون محددون. إجراء التحقيق يعادل المراقب يسجل الموضوع. ثم هذا الرسم التخطيطي للفصل هو كما يلي:
باستخدام Java API لتنفيذ وصف الرمز على النحو التالي:
الحزمة المراقب ؛ استيراد java.util.list ؛ استيراد java.util.observable ؛ استيراد java.util.observable ؛ / ***الوصف: الشرطة Zhang San*/ Public Class Police تمتد على {Private String Time ؛ الشرطة العامة (قائمة <Soberver> قائمة) {super () ؛ لـ (Observer O: List) {AddObserver (O) ؛ }} تغيير الفراغ العام (وقت السلسلة) {this.time = time ؛ setChanged () ؛ eletforeBservers (this.time) ؛ }} الحزمة المراقب ؛ استيراد java.util.observable ؛ استيراد java.util.observer ؛ / ** *الوصف: Undercover A */ Public Class undercovera ينفذ Observer {Private String Time ؛ Override public void update (يمكن ملاحظة O ، كائن Arg) {time = (string) arg ؛ System.out.println ("كشف A استلم رسالة ، ووقت الإجراء هو:"+الوقت) ؛ }} الحزمة المراقب ؛ استيراد java.util.observable ؛ استيراد java.util.observer ؛ / ** *الوصف: Undercover B */ Public Class undercoverb تنفذ Observer {Private String Time ؛ Override public void update (يمكن ملاحظة O ، كائن Arg) {time = (string) arg ؛ System.out.println ("استقبل الكشف B رسالة ، وكان وقت الإجراء:"+الوقت) ؛ }} الحزمة المراقب ؛ استيراد java.util.arraylist ؛ استيراد java.util.list ؛ استيراد java.util.observer ؛ / ***الوصف: اختبار*/ عميل الفئة العامة {/ ***param args*/ public static void main (string [] args) {undercovera o1 = new undercovera () ؛ undercoverb o2 = جديد undercoverb () ؛ قائمة <Soncerver> list = new ArrayList <> () ؛ list.add (O1) ؛ list.add (O2) ؛ موضوع الشرطة = الشرطة الجديدة (قائمة) ؛ الموضوع. Change ("02:25") ؛ System.out.println ("========================== بسبب المعلومات التي يتم عرضها ، وقت الإجراء هو متقدم ==================================================================== ؛ نتائج تشغيل التشغيل:
تلقى Undercover B الرسالة ، ووقت الإجراء هو: 02:25 Undercover A للرسالة ، ووقت الإجراء هو: 02:25 ========================== extrem
4. ملخص
يحدد نمط المراقب علاقة واحدة إلى حد بين الكائنات. عندما تتغير حالة كائن (المراقب) ، سيتم إخطار الكائنات التي تعتمد عليها. يمكن تطبيقه على النشر ، والاحتفاظ بتغيير في سيناريوهات الأعمال هذه.
يستخدم المراقب طريقة اقتران فضفاضة. لا يعرف المراقب تفاصيل المراقب ، لكنه يعلم فقط أن المراقب قد نفذ الواجهة.
يعد النموذج القائم على الحدث أكثر مرونة ، لكنه يدفع أيضًا تكلفة تعقيد النظام ، لأنه يتعين علينا تخصيص مستمع وحدث لكل مصدر حدث ، مما سيزيد من العبء على النظام.
يتمثل جوهر نموذج المراقب أولاً في التمييز بين الدور ووضع المراقب والمراقب ، وهم علاقة كثيرة. مفتاح التنفيذ هو إنشاء اتصال بين المراقب والمراقب. على سبيل المثال ، هناك مجموعة في فئة Observer التي يتم استخدامها لتخزين المراقب ، ويجب إخطار جميع المراقبين عندما يتغير الشيء المكتشف. في مُنشئ المراقب ، سيتم تمريره بواسطة المراقب وسيقوم أيضًا بتسجيل نفسه في قائمة المراقبين المملوكة للمراقب ، أي قائمة المراقبين.
1. مزايا وضع المراقب:
(1) المواضيع المجردة تعتمد فقط على المراقبين التجريديين (2) يدعم وضع المراقب اتصالات البث (3) وضع المراقب يفصل طبقة توليد المعلومات وطبقة الاستجابة
2. عيوب وضع المراقب:
(1) إذا تم تسجيل موضوع ما من قبل عدد كبير من المراقبين ، فسيكلف سعرًا أعلى لإخطار جميع المراقبين (2) إذا تم حظر طريقة الاستجابة لبعض المراقبين ، فسيتم حظر عملية الإخطار بأكملها ، ولا يمكن إخطار المراقبين الآخرين في الوقت المناسب.