نمط Observer
جزء من قسم البرمجة كائنية التوجه في رحلة Python على Coddy. الدرس 47 من 64.
ينشئ نمط المراقب علاقةً واحدًا إلى متعدد، حيث يُخطِر كائن واحد (الموضوع) عدة كائنات (المراقبين) عند تغيّر حالته.
إليك فئة Subject بسيطة تدير المراقبين:
class Subject:
def __init__(self):
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)يحتفظ الموضوع بقائمة من المراقبين ويمكنه إخطارهم جميعًا دفعةً واحدة.
أنشئ فئات مراقِبة بسيطة:
class EmailNotifier:
def update(self, message):
print(f"Email sent: {message}")
class SMSNotifier:
def update(self, message):
print(f"SMS sent: {message}")يمتلك كل مراقب طريقة update يتم استدعاؤها عند إخطاره.
استخدم نمط المراقب:
# إنشاء الموضوع
news = Subject()
# إنشاء المراقبين
email = EmailNotifier()
sms = SMSNotifier()
# إضافة المراقبين إلى الموضوع
news.add_observer(email)
news.add_observer(sms)
# إخطار جميع المراقبين
news.notify("Breaking news: Python is awesome!")أنشئ مثالًا عمليًا باستخدام متتبّع لسعر سهم:
class Stock:
def __init__(self, symbol, price):
self.symbol = symbol
self._price = price
self._observers = []
def add_observer(self, observer):
self._observers.append(observer)
def set_price(self, price):
self._price = price
self.notify()
def notify(self):
for observer in self._observers:
observer.update(self.symbol, self._price)
class Investor:
def __init__(self, name):
self.name = name
def update(self, symbol, price):
print(f"{self.name} notified: {symbol} is now ${price}")
# استخدم متتبع الأسهم
apple_stock = Stock("AAPL", 150)
investor1 = Investor("Alice")
investor2 = Investor("Bob")
apple_stock.add_observer(investor1)
apple_stock.add_observer(investor2)
apple_stock.set_price(155) # يُخطر جميع المستثمرينالإخراج:
Email sent: Breaking news: Python is awesome!
SMS sent: Breaking news: Python is awesome!
Alice notified: AAPL is now $155
Bob notified: AAPL is now $155النقطة الأساسية: يتيح نمط المراقب لكائن واحد إخطار العديد من الكائنات الأخرى تلقائيًا عند حدوث تغيير ما. يحتفظ الموضوع بقائمة من المراقبين ويستدعي أسلوب update الخاص بهم عند الحاجة. يُعد هذا مفيدًا للإشعارات وأنظمة الأحداث والحفاظ على مزامنة أجزاء متعددة من تطبيقك.
التحدي
متوسطنفّذ نمط المراقب من خلال إنشاء نظام لمراقبة الطقس. تحتاج إلى إنشاء فئتين في المناطق المحددة من الكود.
الخطوة 1: إنشاء الفئة WeatherStation
اكتب الفئة WeatherStation الخاصة بك حيث يشير التعليق. يجب أن تقوم هذه الفئة بما يلي:
- الوراثة من الفئة Subject (استخدم
class WeatherStation(Subject):) - التهيئة باستخدام:
- استدعِ مُنشئ الفئة الأصلية باستخدام
super().__init__() - اضبط درجة الحرارة الأولية على 0 باستخدام السمة ذات الشرطة السفلية المفردة
self._temperature(وهي اصطلاح Python للسمة الداخلية)
- استدعِ مُنشئ الفئة الأصلية باستخدام
- تنفيذ
<strong>set_temperature(self, temperature)</strong>:- حدّث سمة درجة الحرارة الداخلية
- استدعِ
self.notify(self._temperature)لإشعار جميع المراقبين
- تنفيذ
<strong>get_temperature(self)</strong>:- أعد قيمة درجة الحرارة الحالية
الخطوة 2: إنشاء الفئة WeatherDisplay
اكتب الفئة WeatherDisplay الخاصة بك حيث يشير التعليق. يجب أن تقوم هذه الفئة بما يلي:
- الوراثة من الفئة Observer (استخدم
class WeatherDisplay(Observer):) - التهيئة باستخدام:
- اقبل مُعامل
name - خزّن الاسم في
self.name
- اقبل مُعامل
- تنفيذ
<strong>update(self, temperature)</strong>:- اطبع رسالة تحديث درجة الحرارة بالتنسيق الدقيق الموضح أدناه
تنسيق الرسالة:
عندما تتلقى شاشة عرض تحديثًا لدرجة الحرارة، يجب أن تطبع النص التالي تمامًا:
Display [name]: Current temperature is [temperature]Cمثال على الاستخدام:
# Create weather station and displays
station = WeatherStation()
phone_display = WeatherDisplay("Phone")
tablet_display = WeatherDisplay("Tablet")
# Attach displays to station
station.attach(phone_display)
station.attach(tablet_display)
# Update temperature - both displays will be notified
station.set_temperature(25.5)
# Output:
# Display Phone: Current temperature is 25.5C
# Display Tablet: Current temperature is 25.5Cملاحظات مهمة:
- تم تنفيذ الطريقتين
attach()وdetach()مسبقًا في الفئة الأساسية Subject، ولا تحتاج إلى تنفيذهما أو استدعائهما في الفئة WeatherStation - في مثال الاستخدام أعلاه، يتم استدعاء
station.attach(phone_display)من قِبل مستخدم فئتك، وليس داخل تنفيذ WeatherStation - تحتاج WeatherStation فقط إلى استدعاء
self.notify()عند تغيّر درجة الحرارة، بينما تتولى الفئة الأساسية Subject الباقي - ركّز على تنفيذ الطرق الثلاث المطلوبة في WeatherStation والطريقتين المطلوبتين في WeatherDisplay كما هو موضح أعلاه
جرّب بنفسك
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self, data):
for observer in self._observers:
observer.update(data)
class Observer:
def update(self, data):
pass
# اكتب فئة WeatherStation الخاصة بك هنا
# اكتب فئة WeatherDisplay الخاصة بك هنا
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكالتدرّب بنفسك: مترجم Python عبر الإنترنت