Menu
Coddy logo textTech

Wzorzec Observer

Część sekcji Programowanie obiektowe ścieżki PHP w Coddy. Lekcja 73 z 91.

Wzorzec Obserwator to behawioralny wzorzec projektowy, który ustanawia relację jeden-do-wielu między obiektami. Gdy jeden obiekt (podmiot) zmienia stan, wszystkie obiekty od niego zależne (obserwatorzy) są automatycznie powiadamiane i aktualizowane.

Pomyśl o subskrypcji newslettera. Newsletter jest podmiotem, a subskrybenci są obserwatorami. Gdy ukazuje się nowe wydanie, wszyscy subskrybenci otrzymują je automatycznie, bez konieczności poznawania przez newsletter szczegółów dotyczących każdego subskrybenta.

Oto podstawowa implementacja w PHP:

<?php
interface Observer {
    public function update(string $message): void;
}

class Newsletter {
    private array $subscribers = [];
    
    public function subscribe(Observer $observer): void {
        $this->subscribers[] = $observer;
    }
    
    public function publish(string $content): void {
        foreach ($this->subscribers as $subscriber) {
            $subscriber->update($content);
        }
    }
}

class EmailSubscriber implements Observer {
    public function __construct(private string $email) {}
    
    public function update(string $message): void {
        echo "Sending to {$this->email}: $message\n";
    }
}

$newsletter = new Newsletter();
$newsletter->subscribe(new EmailSubscriber("alice@example.com"));
$newsletter->subscribe(new EmailSubscriber("bob@example.com"));
$newsletter->publish("New article released!");

Wynik:

Sending to alice@example.com: New article released!
Sending to bob@example.com: New article released!

Ten wzorzec oddziela podmiot od jego obserwatorów. Klasa Newsletter nie musi wiedzieć, czy powiadamia subskrybentów e-maili, subskrybentów SMS-ów czy usługi powiadomień push. Po prostu wywołuje update() na wszystkim, co implementuje interfejs Observer. Dzięki temu dodawanie nowych typów obserwatorów jest łatwe i nie wymaga modyfikowania istniejącego kodu.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system alertów o cenach akcji z wykorzystaniem wzorca Obserwator. Gdy cena akcji się zmieni, wszyscy zarejestrowani inwestorzy powinni automatycznie otrzymać powiadomienie — to doskonałe zastosowanie tego wzorca w prawdziwym świecie.

Rozmieścisz kod w czterech plikach:

  • Observer.php: Zdefiniuj interfejs Observer z jedną metodą update(string $stockName, float $price): void. To kontrakt, którego muszą przestrzegać wszyscy obserwatorzy, aby otrzymywać powiadomienia.
  • Investors.php: Dołącz plik Observer i utwórz dwie klasy implementujące ten interfejs:
    • EmailInvestor: Przyjmuje adres e-mail w konstruktorze (użyj promocji właściwości konstruktora). Jego metoda update() wyświetla "Email to [email]: [stockName] is now $[price]"
    • SmsInvestor: Przyjmuje numer telefonu w konstruktorze. Jego metoda update() wyświetla "SMS to [phone]: [stockName] is now $[price]"
  • Stock.php: Dołącz plik Observer i utwórz klasę Stock, która pełni rolę podmiotu. Twoja akcja powinna:
    • Przechowywać nazwę akcji i jej bieżącą cenę (użyj promocji właściwości konstruktora dla nazwy, zainicjuj cenę wartością 0.0)
    • Utrzymywać prywatną tablicę obserwatorów
    • Mieć metodę subscribe(Observer $observer): void do dodawania obserwatorów
    • Mieć metodę setPrice(float $price): void, która aktualizuje cenę i powiadamia wszystkich obserwatorów
    Podczas powiadamiania obserwatorów wywołaj metodę update() każdego obserwatora, przekazując nazwę akcji i nową cenę.
  • main.php: Dołącz pliki Investors i Stock. Otrzymasz trzy dane wejściowe: nazwę akcji, adres e-mail i numer telefonu.

    Utwórz obiekt Stock z podaną nazwą. Zasubskrybuj EmailInvestor z adresem e-mail oraz SmsInvestor z numerem telefonu.

    Ustaw cenę akcji na 150.50, aby wywołać powiadomienia dla wszystkich subskrybentów.

Wzorzec Obserwator pozwala oddzielić klasę Stock od konkretnych metod powiadamiania. Możesz później łatwo dodać PushInvestor lub SlackInvestor, nie modyfikując przy tym klasy Stock.

Spróbuj swoich sił

<?php
require_once 'Investors.php';
require_once 'Stock.php';

// Wczytaj dane wejściowe
$stockName = trim(fgets(STDIN));
$email = trim(fgets(STDIN));
$phone = trim(fgets(STDIN));

// TODO: Utwórz Stock o podanej nazwie

// TODO: Zapisz EmailInvestor, używając adresu e-mail

// TODO: Zapisz SmsInvestor, używając numeru telefonu

// TODO: Ustaw cenę akcji na 150.50, aby wywołać powiadomienia
?>
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 PHP online