W aplikacjach często wykorzystuje się kolekcje takie jak List, Set, Map czy pochodne. W kolekcjach tych przetrzymuje się obiekty różnego typu. Nie jednokrotnie także buduje się kolekcje o budowie hierarchicznej, np. za pomocą wzorca Composite. Są sytuajcje, gdy musimy przeiterować się po takiej kolekcji w jakimś celu i wykonać na każdym obiekcie jakąś metodę. Np. w sytuacji przeindeksowania, lub przywrócenia utraconych danych. Problem w tym, że kolekcja jak wspomniano może zawierać kilka różnych obiektów i każdy powinien być traktowany inaczej. Korzystanie w takiej sytuacji z instanceof nie jest do końca zgodne z myślą projektowania obiektowego. Zatem co? Zatem wzorzec Visitor.
Visitor jest wzorcem operacyjnym, który potrafi wykonać daną operację na całej strukturze obiektów. Visitor pozwala na zdefiniowanie nowych operacji na elementach struktury, bez zmiany klas tych elementów.

We wzorcu mamy aktorów:

  • Visitor: interfejs który definiuje metody dla wszystkich odwiedzanych obiektów. metody powinny być przeciążane aby miały taką samę nazwę. Wybór metody zależny jest od obiektu który jest podany jako parametr.
  • ConcreteVisitor – implementacja interfejsu Visitor. Każdy ConcreteVisitor jest budowany dla różnego rodzaju operacji, możemy w systemie zbudować kilka Visitorów i każdy będzie do innego celu.
  • Visitable – abstakcja – interfejs który jest implementowany przez obiekty, które mają być wizytowane. każdy obiekt kolekcji powinien implementować ten interfejs.
  • ConcreteVisitable – Klasy implementujące interfejs Visitable definiujące metodę accept(). Visitor poprzez tą metode dostaje się do wnętrza obiektu wizytowanego.
  • ObjectStruture – Klasa zawierająca wszystki obiekty, które moga być odwiedzone. Klasa udostępnia iterator, który pozwala na przemieszczanie sie między kolejnymi składnikami kolekcji. ObjectStructure może być klasą lub całą strukturą klas jak np. Composite.

Sprawdźmy:

Posiadamy sklep internetowy: Część struktury składa się z następujących elementów:
GrupaKlientów, Klient, Zamówienie i Przedmiot. Każde zamówienie posiada co najmniej jedne przedmiot. Każdy klient posiada conajmniej jedno zamówienie.
Chcemy wygenerować raporty dotyczące grup użytkowników naszego sklepu.

Tworzym dwa interfejsy : Visitor i Visitable.
Musimy utworzyć klasę zbierającą dane (ZbieraczDanych), która będzie Visitorem.
Klasy GrupaKlientów, Klient, Zamówienie i Przedmiot muszą implementować interfejs Visitable.
Klasa kliencka która zarządza całością.

Sprawdźmy jak to wygląda:

Diagram wzorca:


.