תבנית 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)הנושא שומר רשימה של משקיפים ויכול להודיע לכולם בבת אחת.
צרו מחלקות Observer פשוטות:
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נקודה מרכזית: תבנית Observer מאפשרת לאובייקט אחד להודיע אוטומטית לאובייקטים רבים אחרים כשמשהו משתנה. הנושא מנהל רשימה של צופים וקורא למתודת update שלהם בעת הצורך. הדבר שימושי להתראות, למערכות אירועים ולשמירה על סנכרון בין חלקים שונים של היישום.
אתגר
בינוניממשו את תבנית Observer על ידי יצירת מערכת לניטור מזג האוויר. עליכם ליצור שתי מחלקות באזורים המיועדים בקוד.
שלב 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)
קבצים חיצונייםמבוא ל-OOPמחלקות לעומת אובייקטיםהפרמטר selfמתודותמאפייניםשיטת הבנאי (__init__)חזרה: מחשבון פשוט5פולימורפיזם
בחינה מחדש של דריסת מתודותטיפוסיות ברווזמחלקות ומתודות אבסטרקטיותעיצוב ממשקיםסיכום – מחשבון צורות8מושגים מתקדמים בתכנות מונחה עצמים
קומפוזיציה לעומת הורשהMixinsמתודות סטטיות ומתודות מחלקהדקורטורים למחלקותמנהלי הקשרתרגלו בעצמכם: קומפיילר Python אונליין