Wzorzec Observer w JavaScripcie.

W dzisiejszym poście pokażę jak zaimplementować wzorzec Observer w JavaScripcie. Ten bardzo przydatny mechanizm jest jednym z najczęściej wykorzystywanych wzorców w JS.

Pomimo iż implementacja JSowa, nie może być idealną wersją Observera (brak klas i interfejsów), naprawdę warto znać logikę, która stoi za tym rozwiązaniem. Mogę zagwarantować, że prędzej czy później trafisz na problem, który bardzo łatwo rozwiązać stosując Observera.

Wzorzec Observer w JavaScripcie.

Observer to wzorzec projektowy, w którym jeden obiekt, obiekt obserwowany, zarządza listą innych obiektów (obserwujących). Obiekt obserwowany jest w stanie dowolnie dodawać lub usuwać ze swojej listy obiekty obserwujące. Najważniejszą cechą tego wzorca jest to, że obiekt obserwowany, może powiadamiać obiekty obserwujący o wszystkich zmianach jakie zachodzą w jego ekosystemie.

Działa to na zasadzie powiadomień jeden do wielu. Jeden obiekt obserwowany może w ten sposób kontrolować stan obiektów obserwujących. Aby stać się elementem obserwującym, obiekt musi mieć odpowiednie API / interfejs.

W bibliotece jQuery, przypisywanie eventów w stylu onClick do elementów DOMu, działa właśnie przy użyciu tego wzorca. Sporo Observera jest też używane w nowoczesnych frameworkach typu MVVM (Model View View-Model). To właśnie ta mechanika jest odpowiedzialna za takie cuda jak ciągłe powiązanie zawartości dokumentów HTML z obiektami JavaScriptowymi.

Skoro teorie mamy już za sobą czas przejść do konkretów. Oto bardzo prosta implementacja Observera w JavaScript:

Na wzorzec składają się dwa elementy. Moduł tworzący obiekt obserwowany oraz „interfejs” dla obiektów obserwujących.

Obiekt obserwowany

Moduł zawiera trzy elementy prywatne. Pierwszy z nich to pole observerList zawierające tablice do przechowywania referencji do obiektów obserwujących. Dwa pozostałe elementy to metody add oraz remove służące do usuwania oraz dodawania obiektów obserwujących z listy. Dodatkowo, metoda add ‚oznacza’ nadany jej obiekt, dodając do niego specjalne pole obsID, którego wartość to indeks referencji obiektu wewnątrz tablicy observerList. Pole to jest następnie używane w metodzie remove, do usunięcia obiektu z tablicy.

Zwracane przez moduł API, zawiera trzy metody. Dwie z nich, addObserver oraz removeObserver to publiczne aliasy prywatnych funkcji służących do zarządzania listą elementów obserwujących. Trzecia metoda, notify, służy do powiadamiania zainteresowanych obiektów. Przechodzi ona przez tablicę observerList i wywołuje metodę update na jej elementach, czyli obiektach obserwujących.

To, co dokładnie robić będą metody notify oraz update, zależy już od konkretnej implementacji Observera. W moim przypadku, notify po prostu przekazuje do obiektów obserwujących jakiś tekst a update drukuje ten tekst do konsoli. Można sobie wyobrazić to jako serwer przekazujący wiadomości do czatu internetowego.

Obiekty obserwujące

We wzorcu Oberver, dodatkowym przydatnym założeniem jest to, że elementami obserwującymi może stać się każdy obiekt w programie, niezależnie od tego jak wygląda. W klasycznych językach takich jak Java osiąga się to poprzez dołączanie do obiektu specjalnego interfejsu. Powoduje on, że dany obiekt musi mieć zdefiniowane metody potrzebne do obsługi mechanizmów observera. W JS nie ma takich narzędzi, więc musiałem poradzić sobie inaczej.

Stworzyłem prosty moduł, zwierający definicje metody update. W JS do obiektów można dodawać pola, w każdym momencie działania programu. Dzięki temu mogę po prostu przypisywać do obiektów referencje do metody z mojego ‚interfejsu’. Dzięki temu, w razie konieczności zmiany działania API Observera, metodę update muszę zmienić tylko w jednym miejscu. Oczywiście nic nie stoi na przeszkodzie, aby dla niektórych obiektów tworzyć osobne implementacje tej metody. Jednak wtedy będziemy wchodzić na grząski grunt i polecałbym być ostrożnym.

A oto przykład, jak można wykorzystać przedstawioną implementację:

Najpierw tworzę instancję obiektu obserwowanego i przypisuje ją do zmiennej subj. Następnie dodaję do programu dwa różne od siebie obiekty. Gdy są gotowe, tworzę w nich pole update, do którego przypisuję referencje do update z mojego ‚interfejsu’.

Następnie dodaję oba obiekty do listy elementów obserwujących subj. Teraz wystarczy, że wywołam metodę notify.

W konsoli pojawią się dwa wpisy, świadczące o tym, że obiekty obserwujące otrzymały wiadomość.

I to wszystko na dziś. Należy pamiętać, że jest to bardzo prosta implementacja tego wzorca. Na pewno dałoby się ją jeszcze usprawnić, lub napisać zupełnie inaczej. Ważne jednak jest zrozumienie podstawowych zachowań tego mechanizmu. W razi jakichkolwiek niejasności, zapraszam do pozostawienia wpisu w komentarzach. Chętnie odpowiem na wszelkie pytania.

Na koniec, jak zawsze, zachęcam do polubienia mojej strony na facebooku. Zawsze na bieżąco zamieszczam tam informacje o nowościach, więc warto polubić aby nie przegapić żadnego nowego wpisu.

3 thoughts on “Wzorzec Observer w JavaScripcie.”

  1. Przystepnie wyjasnione wzorce projektowe. W srode mam rozmowe na stanowisko juniorskie, gdzie m.in. wymagaja znajomosci wzorcow 🙂 Czytajac Twoje posty juz kilka poznalem – dzieki!

  2. Czesc,

    Chcialem Cie zapytac o zapis przy funkcji usuwającej:

    delete obj.obsId
    observerList.splice(obj.obsId,1);

    Wpierw usuwasz identyfikator, a pozniej uzywasz go do usuniecia obiektu z tablicy? Czy czegos nie zlapalem 🙂

    Swoją drogą, fajnie pokazane, dzięki!

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *