Wzorzec Observer
Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 47 z 64.
Wzorzec Obserwator tworzy relację jeden-do-wielu, w której jeden obiekt (podmiot) powiadamia wiele obiektów (obserwatorów), gdy zmienia się jego stan.
Oto prosta klasa Subject, która zarządza obserwatorami:
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)Podmiot przechowuje listę obserwatorów i może powiadomić ich wszystkich jednocześnie.
Utwórz proste klasy obserwatorów:
class EmailNotifier:
def update(self, message):
print(f"Email sent: {message}")
class SMSNotifier:
def update(self, message):
print(f"SMS sent: {message}")Każdy obserwator ma metodę update, która jest wywoływana po otrzymaniu powiadomienia.
Użyj wzorca obserwatora:
# Utwórz podmiot
news = Subject()
# Utwórz obserwatorów
email = EmailNotifier()
sms = SMSNotifier()
# Dodaj obserwatorów do podmiotu
news.add_observer(email)
news.add_observer(sms)
# Powiadom wszystkich obserwatorów
news.notify("Breaking news: Python is awesome!")Utwórz praktyczny przykład z modułem śledzenia cen akcji:
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}")
# Użyj narzędzia do śledzenia akcji
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) # Powiadamia wszystkich inwestorówWynik:
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 $155Kluczowa informacja: Wzorzec Obserwator pozwala jednemu obiektowi automatycznie powiadamiać wiele innych, gdy coś się zmieni. Podmiot przechowuje listę obserwatorów i w razie potrzeby wywołuje ich metodę update. Przydaje się to do powiadomień, systemów zdarzeń i synchronizowania wielu części aplikacji.
Wyzwanie
ŚredniZaimplementuj wzorzec Obserwator, tworząc system monitorowania pogody. Utwórz dwie klasy w wyznaczonych obszarach kodu.
Krok 1: Utwórz klasę WeatherStation
Napisz swoją klasę WeatherStation w miejscu wskazanym przez komentarz. Klasa powinna:
- Dziedziczyć po klasie Subject (użyj
class WeatherStation(Subject):) - Inicjalizować się z:
- Wywołaniem konstruktora klasy nadrzędnej za pomocą
super().__init__() - Ustawieniem początkowej temperatury na 0 za pomocą atrybutu z pojedynczym podkreśleniem
self._temperature(zgodnie z konwencją Pythona dotyczącą atrybutu wewnętrznego)
- Wywołaniem konstruktora klasy nadrzędnej za pomocą
- Zaimplementować
<strong>set_temperature(self, temperature)</strong>:- Zaktualizować wewnętrzny atrybut temperatury
- Wywołać
self.notify(self._temperature), aby powiadomić wszystkich obserwatorów
- Zaimplementować
<strong>get_temperature(self)</strong>:- Zwrócić bieżącą wartość temperatury
Krok 2: Utwórz klasę WeatherDisplay
Napisz swoją klasę WeatherDisplay w miejscu wskazanym przez komentarz. Klasa powinna:
- Dziedziczyć po klasie Observer (użyj
class WeatherDisplay(Observer):) - Inicjalizować się z:
- Przyjąć parametr
name - Zapisać nazwę jako
self.name
- Przyjąć parametr
- Zaimplementować
<strong>update(self, temperature)</strong>:- Wypisać komunikat o aktualizacji temperatury w dokładnie takim formacie, jaki pokazano poniżej
Format komunikatu:
Gdy wyświetlacz otrzyma aktualizację temperatury, musi wypisać dokładnie:
Display [name]: Current temperature is [temperature]CPrzykładowe użycie:
# 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.5CWażne uwagi:
- Metody
attach()idetach()są już zaimplementowane w klasie bazowej Subject — nie musisz ich implementować ani wywoływać w swojej klasie WeatherStation - W powyższym przykładzie użycia
station.attach(phone_display)jest wywoływane przez użytkownika Twojej klasy, a nie wewnątrz implementacji WeatherStation - Twoja klasa WeatherStation musi jedynie wywołać
self.notify(), gdy zmieni się temperatura — klasa bazowa Subject zajmie się resztą - Skup się na zaimplementowaniu trzech wymaganych metod w klasie WeatherStation i dwóch wymaganych metod w klasie WeatherDisplay, zgodnie z powyższą specyfikacją
Spróbuj swoich sił
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
# Napisz tutaj swoją klasę WeatherStation
# Napisz tutaj swoją klasę WeatherDisplay
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektyParametr selfMetodyAtrybutyMetoda konstruktora (__init__)Powtórzenie – prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaFunkcja super()Nadpisywanie metodDziedziczenie wielokrotneKolejność rozwiązywania metodPodsumowanie – hierarchia pracowników7Metody specjalne
Wprowadzenie do metod magicznychPrzeciążanie operatorówMagiczne metody kontenerówPowtórka – własna lista10Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy2Dekoratory
Wprowadzenie do dekoratorówDekorator propertyDekorator metody statycznejDekorator metody klasowej5Polimorfizm
Ponowne omówienie nadpisywania metodTypowanie kaczeKlasy i metody abstrakcyjneProjektowanie interfejsówPodsumowanie — kalkulator kształtów8Zaawansowane koncepcje programowania obiektowego
Kompozycja a dziedziczenieMiksyMetody statyczne i klasoweDekoratory klasMenedżery kontekstu11Wzorce projektowe, część 2
Wzorzec PolecenieWzorzec AdapterWzorzec DekoratorWzorzec Metoda szablonowaWzorzec StanWzorzec Kompozyt3Właściwości klas
Zmienne instancji a zmienne klasoweDekoratory właściwościAtrybuty prywatnePowtórzenie — menedżer kont bankowych6Hermetyzacja
Public, Protected, Private — pamięćModyfikatory dostępuUkrywanie informacjiDekoratory właściwości — zaawansowanePodsumowanie — system ewidencji uczniów12Projekt: System zarządzania biblioteką
Przegląd projektuKlasy Book i UserSystem wypożyczeńFunkcja wyszukiwaniaInterfejs administratoraTestowanie i integracjaPoćwicz samodzielnie: Kompilator Python online