Menu
Coddy logo textTech

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ów

Wynik:

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

Kluczowa 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.

challenge icon

Wyzwanie

Średni

Zaimplementuj 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)
  • 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
  • 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]C

Przykł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.5C

Ważne uwagi:

  • Metody attach() i detach() 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

quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Python online