Wzorce projektowe: Odwiedzający(Visitor)

Bierzemy się za kolejny wzorzec projektowy, a jest nim Odwiedzający(Visitor) teraz wpisy mogą być nieregularnie, trochę mam zajęć, ale serię o wzorcach projektowych i tak skończę 🙂 Jedziemy z tematem 🙂

 

Dyskusja

Głównym celem wzorca odwiedzającego(Visitor) jest dodawania nowych funkcjonalności do istniejącego obiektu bez modyfikowania klasy na których ten obiekt operuje. Jak widać wzorzec ten nie narusza zasady open-closed, tak jak to widać na obrazku poniżej 🙂 .

Implementacja w skrócie wygląda tak, że klasa Visitor deklaruje metodę visit(), której argumentem jest jakiś element struktury oraz elementy struktury deklarują metodę accept(), która za argument przyjmuję klasę Visitor, metoda accept() wywołuje metodę visit() w klasie Visitor w zależności od typu przekazanego argumentu.

Odwiedzający(Visitor) dobrze współpracuje z Kompozytem(Composite), więc w praktyce można ich razem użyć do zarządzania np strukturą pracowników w firmie. Kompozyt odpowiada za strukturę a Odwiedzający za przydzielanie zadań do każdego z pracowników.

 

Cel

  • Reprezentuje operacje wykonywane na obiektach struktury również pozwala na zdefiniowanie nowej operacji bez zmieniania klasy elementu na którym operuje.
  • Oddziela algorytm od struktury na której operuje.
  • Double dispatch(Podwójna wysyłka), czyli wywoływanie metod odwiedzającego w zależności od typu parametru przekazanego do metody w skrócie przeciążanie(overloading) metod odwiedzającego.

 

Problem

Wiele operacji musi być wykonanych na odrębnych elementach struktury obiektów. W tym przypadku dobrze będzie użyć wzorca Odwiedzający(Visitor), ponieważ w sprawny sposób klasa Visitor iteruje po każdym elemencie w strukturze obiektów.

 

Użyj wtedy kiedy:

  • Masz strukturę obiektów i na każdym elemencie tej struktury musisz wykonać jakąś operację.
  • Chcesz dodać lub zmienić operacje wykonywaną na elementach struktury bez zmieniania klasy tego elementu.

 

Struktura

Zobaczmy jak wygląda zwykle schemat wzorca Odwiedzający(Visitor)

Visitor scheme

Klient najpierw zapisuje elementy w strukturze, następnie tworzy obiekty klas odwiedzających i po kolei iteruje po elementach struktury.

Zobaczmy jak to w kodzie wygląda, zacznijmy od klasy Visitor oraz klas dziedziczących po niej:

I klasy dziedziczące po klasie Visitor, czyli można powiedzieć konkretni odwiedzający 🙂 implementujący abstrakcyjne metody.

Oraz druga, czyli Visitor2.

Będzimy wywoływać metody w zależności od typu argumentu, czyli w naszym przypadku od nazwy klasy jak widać wykorzystujemy przeciążanie metod.

Zobaczmy teraz jakiej klasy przekazujemy do metod VisitElement(). Mamy najpierw klasę abstrakcyjną Element.

Jak widzimy, mamy zdefiniowaną metodę Accept(), w której będziemy w klasach konkretnych dziedziczących po klasie Element wywoływać metody VisitElement() w zależności od nazwy klasy.

Zobaczmy klasy dziedziczące po klasie Element.

Oraz ElementB.

Jak widać klasy ElementB oraz ElementA wiele się od siebie nie różnią, tylko nazwą klasy, właśnie nazwę klasy będziemy przekazywać jako argument do metody VisitElement(), dzięki czemu kompilator będzie wiedział, którą wersję metody VisitElement() ma wywołać.

Wszystkie utworzone elementy zapisujemy w strukturze obiektów i z tej struktury iterujemy po jej elementach wywołujac metodę Accept().

Elementy struktury tworzymy w kliencie, również z poziomu klienta wywołujemy metodę Accept(), po czym następuje iteracja po elementach tej struktury.

Wynik:

Visitor scheme

 

Czas na suchara 🙂 😂

Wiem, muszę poszukać jakichś leszych żartów 🙂, średni w tym jestem 😂😂

 

Przykład z życia wzięty

Firma transportowa

Zróbmy teraz przykład na zasadzie firmy transportowej. Załóżmy, że potrzebujemy uporządkowanego mechanizmu zamawiania taksówki przez klientów gdzie chcemy mieć konkretną listę klientów i przy każdym zamówieniu klienta będziemy chcieli sprawdzić każdego klienta na jaką taksówkę może sobie pozwolić(innymi słowy czy klient jest przy kasie 🙂 ) oraz do którego klienta przyjechała już taksówka 🙂

Klasa struktury obiektów jest listą klientów, klient jest jednym z elementów tej listy, a taksówka jest przykładem klasy Visitor. Jak to mówią obraz znaczy więcej niż tysiąc słów 🙂

Visitor scheme

Jak w poprzednim przykładzie zacznijmy od odwiedzających w naszym przypadku jest to taxi.

Definiujemy metodę VisitCustomer(), która może przyjąć za argument trzy różne klasy zwykłego klienta, bogatego oraz biednego. Zobaczmy klasy, które implementują metodę VisitCustomer().

Oraz:

Zobaczmy teraz klasy klientów.

Najpierw klasa abstrakcyjna klienta w której są zdefiniowane najważniejsze rzeczy:

RichCustomer

PoorCustomer

TaxiCustomer

Wszyscy klienci są rzecz jasna zapisani w strukturze obiektów.

W kliencie zapisujemy klientów korzystających z usług firmy transportowej w strukturze oraz iterujemy po strukturze klientów.

Wynik:

 

Powiązania z innymi wzorcami

  • Iterator może przeiterować całą strukturę Kompozytu. Odwiedzający może wykonywać operacje na elementach po których iteruje.
  • Odwiedzającego można użyć razem z Iteratorem, żeby móc iterować po strukturze obiektów i wykonywać na niektórych tych obiektach jakieś operacje.
  • Drzewko składni wzorca Interpreter jest Kompozytem, więc Iteratora i Odwiedzającego można również zastosować.

 

Podsumowanie

I to wszystko na temat wzorca Odwiedzający(Visitor)🙂

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

W następnym artykule, będzie mowa o wzorcu Pamiątka(Memento).

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/visitor

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

Post a comment

Be first!

avatar
  Subscribe  
Notify about