W artykule tym zostanie omówiony wzorzec projektowy Obserwator oraz sposób jego użycia w języku C#.
Wielokrotnie w naszej aplikacji może pojawić się potrzeba dokonania aktualizacji danej części aplikacji zmianą status z innej cześci aplikacji. Jedną z możliwości jest przygotowanie specjalnego modułu odbioru powiadomień, który wielokrotnie sprawdza czy nadeszły jakieś aktualizacje. Takie podejście ma jednak dwa główne problemy. Po pierwsze, takie sprawdzanie aktualizacji obciąża procesor a drugi to interwał pomiędzy kolejnymi sprawdzeniami, nie uzyskamy informacji o aktualizacji w trybie natychmiastowym.
Rozwiązaniem takiego problemu jest zastosowanie wzorca Obserwatora. Poniżej diagram klas dla wzorca projektowego:
Omówmy wszystkie klasy jedna po drugiej:
- Subject - klasa ta zawiera listę wszystkich obserwatorów i dostarcza funkcjonalność pozwalającą nam dodawanie lub usuwanie obserwatora. Klasa ta jest również odpowiedzialna za aktualizacje obserwatorów, gdy dochodzi do jakiejś zmiany. W tym celu, w poniższym przykładzie została zaimplementowana klasa ASubject;
- ConcreteSubject - klasa ta jest klasą implementującą Subject. Klasa ta jest encją, której zmiana wpłynie na wszystkie inne obiekty. W poniższym przykładzia została zaimplementowana klasa Dummy w celu osiągnięcia tego samego działania;
- Observer - określa interfejs definiujący metody, które powinny być wywołane, gdy dochodzi do zmiany. W przykładowym projekcie jest to IObserver;
- ConcreteObserver - to jest klasa, która musi aktualizować samą siebie wraz ze zmianą. Klasa ta musi zaimplementować Observer oraz zarejestrować siebie z ConcretSubject, aby otrzymywać powiadomienia. W przykładowej aplikacji do osiągnięcia tego celu została użyta klasa Shop.
Poniżej ten sam diagram, ale po zastosowaniu mojej implementacji:
Zanim przeniesiemy się do właściwego kodu chciałbym wyjaśnić jeszcze jedną rzecz. Na platformie .NET dostępne są delegaty, które są bardzo dobrym przykładem wzorca Obserwatora. Tak naprawdę nie musimy implementować całego wzorca w języku C#, aby używać delegatów do tej samej funkcjonalności – w ramach przykładu dokonamy tej implementacji, aby dobrze zrozumieć ten wzorzec. Ponadto, dokonamy implementacji delegatów w taki sposób, aby współpracowały z wzorcem Obserwatora. Przejdźmy zatem do kodu.