نمط Observer
جزء من قسم Object Oriented Programming في رحلة Python على Coddy — الدرس 47 من 64.
ينشئ نمط المراقب (Observer Pattern) علاقة واحد إلى متعدد حيث يقوم كائن واحد (الموضوع - subject) بإخطار كائنات متعددة (المراقبين - observers) عندما تتغير حالته.
إليك فئة 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)يحتفظ الموضوع بقائمة من المراقبين ويمكنه إخطارهم جميعاً في وقت واحد.
قم بإنشاء فئات مراقب (observer) بسيطة:
class EmailNotifier:
def update(self, message):
print(f"Email sent: {message}")
class SMSNotifier:
def update(self, message):
print(f"SMS sent: {message}")لكل مراقب دالة update يتم استدعاؤها عند التنبيه.
استخدم نمط المراقب (Observer Pattern):
# إنشاء الموضوع
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نقطة رئيسية: يسمح نمط المراقب (Observer Pattern) لكائن واحد بإخطار العديد من الكائنات الأخرى تلقائيًا عند حدوث تغيير ما. يحتفظ الموضوع (subject) بقائمة من المراقبين (observers) ويستدعي أسلوب update الخاص بهم عند الحاجة. هذا مفيد للإشعارات، وأنظمة الأحداث، والحفاظ على مزامنة أجزاء متعددة من تطبيقك.
التحدي
متوسطقم بتنفيذ نمط المراقب (Observer Pattern) من خلال إنشاء نظام لمراقبة الطقس. تحتاج إلى إنشاء فئتين (classes) في المناطق المخصصة من الكود.
الخطوة 1: إنشاء فئة WeatherStation
اكتب فئة WeatherStation الخاصة بك حيث يشير التعليق. يجب أن تقوم هذه الفئة بما يلي:
- الوراثة من فئة Subject (استخدم
class WeatherStation(Subject):) - التهيئة باستخدام:
- استدعاء منشئ الفئة الأم باستخدام
super().__init__() - تعيين درجة الحرارة الأولية إلى 0 باستخدام سمة خاصة
self._temperature
- استدعاء منشئ الفئة الأم باستخدام
- تنفيذ
<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ملاحظات هامة:
- الأساليب (methods)
attach()وdetach()منفذة بالفعل في الفئة الأساسية Subject - لست بحاجة لتنفيذها أو استدعائها داخل فئة WeatherStation الخاصة بك - في مثال الاستخدام أعلاه، يتم استدعاء
station.attach(phone_display)بواسطة مستخدم الفئة الخاصة بك، وليس داخل تنفيذ WeatherStation - تحتاج WeatherStation فقط إلى استدعاء
self.notify()عندما تتغير درجة الحرارة - وتتولى الفئة الأساسية Subject الباقي - ركز على تنفيذ الأساليب الثلاثة المطلوبة في WeatherStation والأسلوبين المطلوبين في WeatherDisplay كما هو محدد أعلاه
ورقة مرجعية
ينشئ نمط المراقب (Observer Pattern) علاقة واحد إلى متعدد حيث يقوم كائن واحد (الموضوع - subject) بإخطار كائنات متعددة (المراقبون - observers) عندما تتغير حالته.
فئة الموضوع (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)فئات المراقب (Observer) مع طريقة update:
class EmailNotifier:
def update(self, message):
print(f"Email sent: {message}")
class SMSNotifier:
def update(self, message):
print(f"SMS sent: {message}")استخدام نمط المراقب:
# إنشاء الموضوع
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}")يتيح نمط المراقب لكائن واحد إخطار العديد من الكائنات الأخرى تلقائياً عند حدوث تغيير ما. يحتفظ الموضوع بقائمة من المراقبين ويستدعي طريقة update الخاصة بهم عند الحاجة.
جرّب بنفسك
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 الخاصة بك هنا
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات OOP
الملفات الخارجيةمقدمة في OOPClasses مقابل Objectsمعامل selfMethodsAttributesدالة البناء (__init__)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسيةدالة ()superإعادة تعريف الدوال (Method Overriding)الوراثة المتعددةترتيب استدعاء الدوال (Method Resolution Order)مراجعة - هيكلية الموظفين5تعدد الأشكال
مراجعة إعادة تعريف الدوالمفهوم Duck Typingالأصناف والدوال المجردةتصميم الواجهاتملخص - حاسبة الأشكال