المراقب (نموذج تصميم)

نموذج المراقب (بالإنجليزية: Observer Pattern) هو أحد نماذج التصميم التي يدير فيها كائن يدعى باسم الهدف (بالإنجليزية: Subject) قائمة من الكائنات الأخرى التي تعتمد عليه وتسمى هذه الكائنات بالمراقبين (بالإنجليزية: Observers)، حيث يقوم بتنبيه هذه الكائنات عند حدوث تغيير في حالته والذي عادةً ما يحصل لدى استدعاء أحد الطرق الخاصة به. يستخدم هذا النموذج بشكل رئيسي في تحقيق أنظمة التحكم بالأحداث الموزعة. كما يعتبر مكوناً رئيسياً من نموذج التصميم المعماري نمط-عرض-متحكم (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', observablesubject = Observable()observer = Observer(subject)subject.notifyObservers('test')