نمط التصميم Observer في Java

نمط المراقبة هو واحد من أنماط تصميم السلوك. يعد نمط تصميم المراقب مفيدًا عندما تكون مهتمًا بحالة كائن وترغب في الحصول على إشعار في كل مرة يحدث فيها أي تغيير. في نمط المراقب، يُطلق على الكائنات التي تراقب حالة كائن آخر اسم المراقبين، والكائن الذي يتم مراقبته يُعرف بـ الموضوع.

نمط تصميم المراقب

وفقًا لـ GoF، يكمن هدف نمط تصميم المراقب في;

تعريف تبعية واحد-إلى-كثير بين الكائنات بحيث عندما يتغير حال كائن واحد، يتم إعلام جميع المعتمدين عليه وتحديثهم تلقائيًا.

الموضوع يحتوي على قائمة من المراقبين لإخطارهم بأي تغيير في حالته، لذا يجب أن يوفر أساليب يمكن من خلالها للمراقبين التسجيل وإلغاء التسجيل. الموضوع يحتوي أيضًا على طريقة لإخطار جميع المراقبين بأي تغيير وإما يمكنه إرسال التحديث أثناء إخطار المراقب أو يمكنه توفير طريقة أخرى للحصول على التحديث. يجب أن يحتوي المراقب على طريقة لتعيين الكائن الذي سيتم مراقبته وطريقة أخرى سيتم استخدامها من قبل الموضوع لإخطارهم بأي تحديثات. توفر جافا منصة مدمجة لتنفيذ نمط المراقب من خلال فئة java.util.Observable وواجهة java.util.Observer. ومع ذلك، لا يُستخدم على نطاق واسع لأن التنفيذ بسيط حقًا وفي معظم الأحيان لا نرغب في الانتهاء من تمديد فئة فقط لتنفيذ نمط المراقب لأن جافا لا توفر التوريث المتعدد في الفئات. تستخدم خدمة رسائل جافا (JMS) نمط التصميم من نوع المراقب بالإضافة إلى نمط الوسيط للسماح للتطبيقات بالاشتراك ونشر البيانات إلى التطبيقات الأخرى. إطارات نموذج-عرض-تحكم (MVC) تستخدم أيضًا نمط المراقب حيث يكون النموذج هو الموضوع والعروض هي المراقبون الذين يمكنهم التسجيل للحصول على إخطار بأي تغيير في النموذج.

مثال على نمط المراقب في جافا

بالنسبة لمثالنا على برنامج مراقبة النمط في جافا، سنقوم بتنفيذ موضوع بسيط ويمكن للمراقبين التسجيل في هذا الموضوع. في كل مرة يتم نشر رسالة جديدة في الموضوع، سيتم إخطار جميع المراقبين المسجلين ويمكنهم استهلاك الرسالة. استنادًا إلى متطلبات الموضوع، إليك واجهة الموضوع الأساسية التي تعرف على الطرق المتفق عليها التي يجب تنفيذها من قبل أي موضوع فعلي.

package com.journaldev.design.observer;

public interface Subject {

	//طرق التسجيل وإلغاء تسجيل المراقبين
	public void register(Observer obj);
	public void unregister(Observer obj);
	
	//طريقة لإخطار المراقبين بالتغيير
	public void notifyObservers();
	
	//طريقة للحصول على التحديثات من الموضوع
	public Object getUpdate(Observer obj);
	
}

الآن سنقوم بإنشاء عقد للمراقب، سيكون هناك طريقة لربط الموضوع بالمراقب وطريقة أخرى يمكن استخدامها من قبل الموضوع لإخطار أي تغيير.

package com.journaldev.design.observer;

public interface Observer {
	
	//طريقة لتحديث المراقب، تستخدم من قبل الموضوع
	public void update();
	
	//ربط مع الموضوع للمراقبة
	public void setSubject(Subject sub);
}

الآن عقدنا جاهز، دعونا نتابع مع التنفيذ الفعلي لموضوعنا.

package com.journaldev.design.observer;

import java.util.ArrayList;
import java.util.List;

public class MyTopic implements Subject {

	private List observers;
	private String message;
	private boolean changed;
	private final Object MUTEX= new Object();
	
	public MyTopic(){
		this.observers=new ArrayList<>();
	}
	@Override
	public void register(Observer obj) {
		if(obj == null) throw new NullPointerException("Null Observer");
		synchronized (MUTEX) {
		if(!observers.contains(obj)) observers.add(obj);
		}
	}

	@Override
	public void unregister(Observer obj) {
		synchronized (MUTEX) {
		observers.remove(obj);
		}
	}

	@Override
	public void notifyObservers() {
		List observersLocal = null;
		//تُستخدم المزامنة للتأكد من عدم إخطار أي مراقب مسجل بعد استلام الرسالة
		synchronized (MUTEX) {
			if (!changed)
				return;
			observersLocal = new ArrayList<>(this.observers);
			this.changed=false;
		}
		for (Observer obj : observersLocal) {
			obj.update();
		}

	}

	@Override
	public Object getUpdate(Observer obj) {
		return this.message;
	}
	
	//طريقة لنشر الرسالة إلى الموضوع
	public void postMessage(String msg){
		System.out.println("Message Posted to Topic:"+msg);
		this.message=msg;
		this.changed=true;
		notifyObservers();
	}

}

تنفيذ الأسلوب لتسجيل المراقب وإلغاء تسجيله بسيط للغاية، الطريقة الإضافية هي postMessage() التي ستُستخدم من قبل تطبيق العميل لنشر رسالة نصية إلى الموضوع. لاحظ المتغير البولياني لتتبع التغيير في حالة الموضوع والذي يُستخدم في إعلام المراقبين. يُطلب هذا المتغير لذلك إذا لم يكن هناك تحديث وقام شخص ما بالاتصال بطريقة notifyObservers()، فإنه لا يُرسل إخطارات زائفة للمراقبين. لاحظ أيضًا استخدام التزامن في الطريقة notifyObservers() لضمان إرسال الإشعار إلى المراقبين المُسجلين فقط قبل نشر الرسالة إلى الموضوع. هذا هو تنفيذ المراقبين الذين سيشاهدون الموضوع.

package com.journaldev.design.observer;

public class MyTopicSubscriber implements Observer {
	
	private String name;
	private Subject topic;
	
	public MyTopicSubscriber(String nm){
		this.name=nm;
	}
	@Override
	public void update() {
		String msg = (String) topic.getUpdate(this);
		if(msg == null){
			System.out.println(name+":: No new message");
		}else
		System.out.println(name+":: Consuming message::"+msg);
	}

	@Override
	public void setSubject(Subject sub) {
		this.topic=sub;
	}

}

لاحظ تنفيذ الطريقة update() حيث يتم استدعاء طريقة getUpdate() من Subject للحصول على الرسالة للاستهلاك. كان بإمكاننا تجنب هذا الاستدعاء عن طريق تمرير الرسالة كمعلمة إلى الطريقة update(). هذا هو برنامج اختبار بسيط لاستهلاك تنفيذ الموضوع لدينا.

package com.journaldev.design.observer;

public class ObserverPatternTest {

	public static void main(String[] args) {
		 // إنشاء الموضوع 
		MyTopic topic = new MyTopic();
		
		 // إنشاء المراقبين 
		Observer obj1 = new MyTopicSubscriber("Obj1");
		Observer obj2 = new MyTopicSubscriber("Obj2");
		Observer obj3 = new MyTopicSubscriber("Obj3");
		
		 // تسجيل المراقبين للموضوع 
		topic.register(obj1);
		topic.register(obj2);
		topic.register(obj3);
		
		 // إلحاق المراقب بالموضوع 
		obj1.setSubject(topic);
		obj2.setSubject(topic);
		obj3.setSubject(topic);
		
		 // التحقق مما إذا كان هناك تحديث متاح 
		obj1.update();
		
		 // الآن قم بإرسال رسالة إلى الموضوع 
		topic.postMessage("New Message");
	}

}

عند تشغيل البرنامج أعلاه، نحصل على الناتج التالي.

Obj1:: No new message
Message Posted to Topic:New Message
Obj1:: Consuming message::New Message
Obj2:: Consuming message::New Message
Obj3:: Consuming message::New Message

تخطيط فئة نمط Java Observer

يُطلق على نمط تصميم المراقب أيضًا باسم نمط النشر والاشتراك. بعض تطبيقاته تشمل؛

  • java.util.EventListener في Swing
  • javax.servlet.http.HttpSessionBindingListener
  • javax.servlet.http.HttpSessionAttributeListener

هذا كل شيء بخصوص نمط تصميم المراقب في جافا، أتمنى أن يعجبك. شارك حبك من خلال التعليقات ومشاركته مع الآخرين.

Source:
https://www.digitalocean.com/community/tutorials/observer-design-pattern-in-java