نموذج المراقب (Observer Pattern) هو أحد نماذج التصميم التي يدير فيها كائن يدعى باسم الهدف (Subject) قائمة من الكائنات الأخرى التي تعتمد عليه وتسمى هذه الكائنات بالمراقبين (Observers)، حيث يقوم بتنبيه هذه الكائنات عند حدوث تغيير في حالته والذي عادةً ما يحصل لدى استدعاء أحد الطرق الخاصة به.[1][2][3] يستخدم هذا النموذج بشكل رئيسي في تحقيق أنظمة التحكم بالأحداث الموزعة. كما يعتبر مكوناً رئيسياً من نموذج التصميم المعماري نمط-عرض-متحكم (MVC). وقد استُخدم هذا النموذج لأول مرة في تصميم بيئة تطوير واجهة المستخدم المبنية على MVC والخاصة بلغة سمول توك. يستخدم نموذج المراقب بشكل واسع في العديد من المكتبات والنظم البرمجية بما في ذلك معظم أدوات تطوير واجهة المستخدم المرئية.
قد يسبب استخدام نموذج المراقب حدوث تسريب في الذاكرة وتعرف هذه المشكلة باسم المستمع المختفي (Lapsed Listener)، يحدث ذلك بسبب الحاجة إلى تسجيل وإلغاء تسجيل المراقب بشكل صريح، وبما أن الهدف سيبقي مراجعاً قوية إلى قائمة مراقبيه فإنه سيمنع بذلك تدميرهم على سبيل المثال من قبل جامع القمامة. يمكن حل هذه المشكلة عبر جعل الهدف يمتلك مراجعاً ضعيفة إلى مراقبيه.
مكونات النموذج
مثال
فيما يلي مثال بلغة جافا يوضح كيفية استخدام نموذج المراقب، في هذا المثال تم قراءة الدخل من لوحة المفاتيح ومعالجة كل سطر كحدث. يستخدم هذا المثال الصفوف java.util.Observer
وjava.util.Observable
. عند إدخال سلسلة محرفية عن طريق System.in
تُستدعى الطريقة notifyObservers
من أجل تنبيه كافة المراقبين إلى حدوث الحدث وذلك عن طريق استدعاء الطرق update
الخاصة بهم.
يتضمن الملف MyApp.java
الطريقة main
التي تستخدم لتشغيل الكود.
/* EventSource.java : اسم الملف */ package org.wikipedia.obs; import java.util.Observable; //تضمين مكتبة المراقب import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class EventSource extends Observable implements Runnable { @Override public void run() { try { final InputStreamReader isr = new InputStreamReader(System.in); final BufferedReader br = new BufferedReader(isr); while (true) { String response = br.readLine(); setChanged(); notifyObservers(response); } } catch (IOException e) { e.printStackTrace(); } } }
/* ResponseHandler.java : اسم الملف */ package org.wikipedia.obs; import java.util.Observable; import java.util.Observer; /* هذا هو معالج الأحداث */ public class ResponseHandler implements Observer { private String resp; public void update(Observable obj, Object arg) { if (arg instanceof String) { resp = (String) arg; System.out.println("\nReceived Response: " + resp ); } } }
/* MyApp.java : اسم الملف */ /* البرنامج الرئيسي هنا */ package org.wikipedia.obs; public class MyApp { public static void main(String[] args) { System.out.println("Enter Text >"); // مصدر الأحداث - قراءة الدخل من مجرى الدخل الرئيسي final EventSource eventSource = new EventSource(); // أنشئ مراقب final ResponseHandler responseHandler = new ResponseHandler(); // سجل المراقب في قائمة مراقبي الأحداث eventSource.addObserver(responseHandler); // شغل خيط مصدر الأحداث Thread thread = new Thread(eventSource); thread.start(); } }
وهذا مثال آخر بلغة بايثون:
class Observable(object): def __init__(self): self.__observers = [] def registerObserver(self, observer): self.__observers.append(observer) def notifyObservers(self, *args, **kwargs): for observer in self.__observers: observer.notify(self, *args, **kwargs) class Observer(object): def __init__(self, observable): observable.registerObserver(self) def notify(self, observable, *args, **kwargs): print 'Got', args, kwargs, 'From', observable subject = Observable() observer = Observer(subject) subject.notifyObservers('test')
انظر أيضاً
مراجع
- "The Observer design pattern - Problem, Solution, and Applicability". w3sDesign.com. مؤرشف من الأصل في 16 مايو 201812 أغسطس 2017.
- "The Observer design pattern - Structure and Collaboration". w3sDesign.com. مؤرشف من الأصل في 21 أغسطس 201712 أغسطس 2017.
- Comparison between different observer pattern implementationsMoshe Bindler, 2015 (Github) نسخة محفوظة 02 مارس 2017 على موقع واي باك مشين.