Wzorce projektowe: Obserwator(Observer)

Cześć znowu!! Dzisiaj bierzemy się za kolejny wzorzec projektowy, który moim zdaniem trzeba znać obowiązkowo 🙂 A jest nim wzorzec obserwator(observer).

 

Dyskusja

Główny cel tego wzorca jest taki np gdy stan jakiegoś obiektu się zmieni, to żeby wszystkie zależności tego obiektu były powiadamiane i aktualizowane. W skrócie wzorzec obserwer działa w sposób, że definiuje Subject, który jest można powiedzieć modelem danych i to w nim jest główna logika która, aktualizuje stany obiektów, po kolei przekazując obiekty Observer. Wzorzec obserwator dobrze współpracuje z wzorcem MVC reprezentując w tym wzorcu widok.

Wzorzec obserwator jest wykorzystywany w facebooku wtedy kiedy np dostajesz powiadomienie o jakimś wydarzeniu albo wtedy kiedy dostajesz powiadomienie, jeśli ktoś inny skomentował jakiś post lub np na youtube kiedy ktoś subskrybuje jakiś kanał.

Zasada działania wzorca obserwator opisuje również obrazek poniżej 😂😂

 

Cel

  • Reprezentuje widok wzorca MVC.
  • Gdy jakiś obiekt zmieni swój stan, wzorzec obserwator ma za zadanie powiadomić i zaktualizować wszystkie zależności tego obiektu automatycznie.
  • Oddziela główną logikę wzorca czyli Subject od zmiennych obiektów Observer.

 

Problem

Posiadasz w jakimś projekcie mechanizm monitorowania, który nie jest skalowalny np wymaga ciągnięcia jakichś zależności lub ciągle są jakieś problemy lub wymagania dotyczące monitorowania.

Weźmy przykład z życia załóżmy, że klient chodzi do sklepu żeby patrzeć czy produkt jest dostępny. Większość tych wycieczek będzie bezsensu, ponieważ w większości przypadków ten produkt nie będzie dostępny. Najlepiej było by gdyby sprzedawca miał jakiś system, którym mógłby powiadamiać klienta o dostępności danego produktu np przez email.

 

Użyj wtedy kiedy:

  • Masz wiele obiektów, które są zależne od jednego obiektu.
  • Potrzebujesz zaimplementować wzorzec MVC w jego implementacji możesz użyć wzorca obserwator. Ponizszy obrazek dobrze to obrazuje.

 

Struktura

A tak wygląda struktura wzorca obserwator.

Jak widać klasy ViewOne oraz ViewTwo dziedziczą po interfejsie Observer, żeby wszystkie posiadały metodę update(), Subject posiadamy zazwyczaj listę w której zapisujemy wszystkie obiekty Observer. Aktualizujemy wszystkie te obiekty wywołujac metodę update() w pętli foreach, która iteruje po kolekcjach będzie wszystko widać zaraz na konkretnym przykładzie 🙂

 

Przykład

Aukcja

Zróbmy najpierw przykład aukcji, licytator zatwierdza coraz większe ceny jakiegoś tam produktu i wysyła komunikat innym obiektom w naszym przykładzie licytującym nową cenę produktu.

Spokojnie 🙂  obserwator to dosyć prosty wzorzec projektowy, więc reakcja w praktycznych przykładach nie powinna być taka jak tego Pana poniżej 😂😂

Zobaczmy kod obiektów obserwujących w naszym przypadku licytujących, zacznijmy od interfejsu Observer, czyli podstawowego elementu klasy we wzorcu obserwator, wygląda on tak:

A klasa licytującego wygląda tak:

W tej klasie rozszerzamy metodę update() i jeśli cena przekroczy 450 to wtedy kończymy licytację.

Zobaczymy teraz klasę licytatora, który również dziedziczy po interfejsie Subject, który to interfejs służy do zaimplementowania metod służących do rejestrowania licytujących oraz powiadamiania ich o nowej cenie.

Najpierw interfejs Subject.

Oraz klasa licytatora w naszym przypadku Auctioneer. Można powiedzieć, że klasa Auctioneer i interfejs Subject to cała nasza główna logika czyli Subject naszego wzorca obserwator 🙂

Jak widać oberwujących zapisujemy w liście observerList. A użytkowników powiadamiamy o nowej cenie wywołując metodę notifyObservers(), która posiada pętlę foreach, która iteruje po liście observerList.

I na końcu klient.

Widać, że tworzymy obiekty obserwujących, podbijamy cenę oraz powiadamiamy o niej obserwujących.

Wynik:

template method scheme

 

Przykład z życia wzięty

Powiadomienia o nowych komentarzach

Zrobimy teraz przykład mechanizmu powiadamiającego o nowych komentarzach pod jakimś postem, podobnie jak to działa na facebooku,

Zacznijmy jak w poprzednim przykładzie od interfejsu Observer i klasy obserwatorów, czyli w naszym przypadku komentujących post.

Interfejs Observer.

Widzimy, że teraz interfejs wygląda trochę inaczej, będzimy musieli wysyłać listę użytkowników żeby powiadomić wszystkich kto inny skomentował post oraz imię użytkownika, przy którym obecnie wykonujemy iterację. Jednak ogólna zasada oberwatora się nie zmienia, podajemy tylko trochę więcej danych.

I klasa obserwatora w naszym przypadku człowieka komentującego.

Ta klasa w skrócie działa tak, że jeśli ludzi komentujących post jest więcej niż jeden to wtedy wyświetlamy ich imiona po kolei, rzecz jasna na końcu funkcji usuwamy z listy imię człowieka po którym obecnie iterujemy, ta osoba, która komentuje po prostu wie, że komentuje dany post 🙂

Zobaczmy teraz klasę, która dziedziczy interfejs Subject, która jak w poprzednim przykładzie służy do zaimplementowania metod powiadamiających i rejestrujących użytkowników w naszym przypadku nazywa się ona FacebookPost.

Wiele ona się nie różni od odpowiednika tej klasy w poprzednim przykładzie Auctioneer, jedynie dodajemy kolejną listę, która zapisuje imiona osób komentujących.

Również interfejs Subject bez większych zmian.

I klient.

Wynik:

template method scheme

Gdybyś jeszcze chciał zabezpieczyć to wielowątkowo to do zmiany byłaby klasa FacebookPost oraz klient.

Zacznijmy od klasy FacebookPost.

Dodałem metodę GetInstance, żeby mogł być tylko jeden obiekt klasy FacebookPost, znamy singletona 🙂. Również dodaliśmy słówko lock, które również było wałkowane wiele razy, w artykule o współbieżności jest wyjaśnienie słówka lock. Dla jeszcze niewiedzących powiem w skrócie, że to słówko zabezpiecza dostęp z dwóch wątków w tej samej chwili. Oczywiście każdy musi dopasować rozwiązanie do swojego języka w javie czy C++ wiadomo, że w tych językach będzie to inaczej wyglądać.

Zobaczmy jeszcze klienta.

Nie jest to zbyt trudne. Po prostu tworzymy wątki za pomocą tasków. Jednak ze względu na naturę asynchoniczności, wszystko jest wykonywane w tej samej chwili, nie wywali się żaden błąd bo już zrobiliśmy odpowiednie zmiany, tylko wynik może inaczej się wyświetlać np tak:

template method scheme

lub tak:

template method scheme

Jeśli chcesz żeby to normalnie się wyświetlało, trzeba wykonywać wątki po kolei, musimy zrobić takie zmiany w kliencie.

I dzięki temu znowu mamy taki wynik 🙂

template method scheme

 

 

Czas na suchara 🙂

Jak się nazywa żona Ryszarda?

MaRYCHA

Dobra wystarczy tych żartów wyjątkowo nieśmiesznych 😐, przejdźmy dalej 🙂

 

Zdarzenia i delegaty w obserwatorze

Powyższe przykłady, które robiliśmy można zrobić również z wykorzystaniem zdarzeń i delegat w C#. Różnica jest jedynie taka, że kod jest bardziej zrozumiały, czytelny i elegancki. Najprostszy przykład poniżej:

Wynik:

template method scheme

Zróbmy teraz przykład z aukcją, jest to pierwszy przykład w tym artykule tylko, że teraz zrobimy ten przykład z wykorzystaniem delegat oraz zdarzeń. Dużo musimy zmienić w klasie Auctioneer oraz tylko trochę musimy zmienić w kliencie oraz interfejsie Subject. 

Najpierw klasa Auctioneer.

Widać, że kodu jest o wiele mniej i jest o wiele bardziej czytelny. I tak ma być 🙂

W interjesie Subject zmieniamy jedynie typ przyjmowanego argumentu w metodzie registerBidder() na NotifyObserver.

W kliencie w wywołaniu metody registerBidder() musimy przekazać jedynie nazwę metody czyli update. Wiadomo jak działają delegaty i eventy 🙂 A jeśli nie to zerknij tutaj 🙂

Jak widać nie musimy przekazywać całego obiektu klasy Bidder, można powiedzieć, że w .NET zostało to zrobione za nas dlatego lubię te platformę, ponieważ skraca wiele rzeczy 🙂

Wynik oczywiście taki sam 🙂

template method scheme

 

Powiązania z innymi wzorcami

  • Mediator może wykorzystać wzorzec obserwator do dynamicznego rejestrowania współpracowników i komunikowania się z nimi.
  • Różnica między mediatorem a obserwatorem jest taka, że obserwator używa do komunikacji obiektów Subject i Observer a mediator hermetyzuje komunikujące się ze sobą obiekty.

 

 

Podsumowanie

I to wszystko na temat wzorca Obserwator(Observer)🙂

Link do githuba ze wszystkimi przykładami:  https://github.com/Slaw145/Observer

W następnym artykule, będzie mowa o wzorcu Odwiedzający(Visitor).

Standardowo, przypominam o newsletterze, którym wysyłam powiadomienia o nowych wpisach oraz dodatkowe informacje na temat, ogółem mówiąc, świecie IT.

KONIECZNIE dołącz do społeczności DevmanCommunity na fb, części społeczności jest w jednym miejscu 🙂

-strona na fb: Devman.pl-Sławomir Kowalski

-grupa na fb: DevmanCommunity

Pytaj, komentuj pod spodem na końcu wpisu, podziel się nim, oceń go, rób co wolisz🙂

Ilustracje, obrazki oraz diagramy są z: https://sourcemaking.com/design_patterns/observer

 
Jeśli ten wpis ci się przydał podziel się nim ze swoimi znajomymi :)

Post a comment

Be first!

avatar
  Subscribe  
Notify about