Na miarę widziałem do tej pory istnieją dwa zastosowania/korzyści dla wzorca projektowego gość:
- Podwójne wysyłki
- odrębne struktury danych z operacjami na nich
Podwójna wysyłka
Załóżmy, że masz klasę pojazdów i klasę VehicleWasher. VehicleWasher ma Wash (Vehicle) metoda:
VehicleWasher
Wash(Vehicle)
Vehicle
Dodatkowo mamy także konkretne pojazdy jak samochód, aw przyszłości będziemy mieć również inne konkretne pojazdy. Do tego mamy klasę samochodu, ale także specyficzną klasę CarWasher który ma działanie specyficzne dla mycia samochodów (pseudo kierunkowym):
CarWasher : VehicleWasher
Wash(Car)
Car : Vehicle
następnie rozważyć następujący kod klienta do mycia konkretny pojazd (zauważ, że x i podkładkę deklarowane są za pomocą ich typ bazowy, ponieważ przypadki mogą być tworzone dynamicznie na podstawie danych wprowadzonych przez użytkownika lub zewnętrznych wartości konfiguracyjnych; w tym przypadku są one po prostu stworzony z nowym operatorem chociaż):
Vehicle x = new Car();
VehicleWasher washer = new CarWasher();
washer.Wash(x);
Wiele języków wykorzystać pojedynczą przesyłkę zadzwonić odpowiednia funkcja. Pojedyncza wysyłka oznacza, że podczas wykonywania tylko jedna wartość jest brana pod uwagę przy określaniu, która metoda wywołać. Dlatego rozważymy tylko właściwy typ płuczki. Rzeczywisty typ x nie jest brany pod uwagę. Ostatni wiersz kodu wywoła CarWasher.Wash (Pojazd) i NOT CarWasher.Wash (Samochód).
Jeśli używasz języka, który nie obsługuje wielu wysyłek i jest ci potrzebna (mogę szczerze powiedzieć, że nigdy nie spotkałem się z taką sytuacją), możesz użyć wzoru projektu gościa, aby to umożliwić. W tym celu należy zrobić dwie rzeczy. Przede wszystkim dodać metodę Accept do klasy nośnika (visitee), która akceptuje VehicleWasher jako gość, a następnie wywołać jego operacji mycia:
Accept(VehicleWasher washer)
washer.Wash(this);
Drugą rzeczą jest to, aby zmodyfikować kod wywołujący i wymienić podkładkę. Przemyć (x); Linia z następujących czynności:
x.Accept(washer);
Teraz po wywołaniu metody zaakceptować rzeczywisty typ x jest uważany (i tylko, że x, ponieważ zakładamy, aby być przy użyciu jednego języka wysyłki). W implementacji metody Accept metoda wywoływania jest wywoływana na obiekcie podkładki (odwiedzającym). W tym celu rozważany jest rzeczywisty typ pralki, co spowoduje wywołanie CarWasher.Wash (Car). Łącząc dwie pojedyncze wysyłki realizowana jest podwójna wysyłka.
Teraz, aby wypowiedzieć się na temat uwagi, takich jak Akceptuj i Odwiedzaj i Użytkownicy są bardzo niespecyficzne. To absolutna prawda. Ale nie bez powodu.
Należy wziąć pod uwagę wymóg w tym przykładzie, aby zaimplementować nową klasę, która jest w stanie naprawić pojazdy: pojazd VehicleRepair. Ta klasa może być używana tylko jako gość w tym przykładzie, jeśli dziedziczy po VehicleWasher i ma logikę naprawy wewnątrz metody Wash. Ale to oczywiście nie ma sensu i byłoby mylące.Tak więc całkowicie zgadzam się, że wzorce projektowe mają na ogół bardzo niejasne i niespecyficzne nazwy, ale czynią je odpowiednimi w wielu sytuacjach. Im dokładniejsze jest twoje nazewnictwo, tym bardziej restrykcyjne może być.
Instrukcja przełącznika uwzględnia tylko jeden typ, który w rzeczywistości jest ręcznym sposobem pojedynczej wysyłki. Zastosowanie wzoru wzoru dla odwiedzających w powyższy sposób zapewni podwójną wysyłkę. W ten sposób niekoniecznie potrzebujesz dodatkowych metod odwiedzania podczas dodawania dodatkowych typów do hierarchii. Oczywiście dodaje trochę skomplikowania, ponieważ sprawia, że kod jest mniej czytelny. Ale oczywiście wszystkie wzory mają swoją cenę.
Oczywiście tego wzoru nie można zawsze użyć. Jeśli spodziewasz się wielu skomplikowanych operacji z wieloma parametrami, nie będzie to dobra opcja.
Alternatywą jest użycie języka, który obsługuje wielokrotną wysyłkę. Na przykład .NET nie obsługiwał go do wersji 4.0, która wprowadziła dynamiczne słowo kluczowe. Następnie w C# można wykonać następujące czynności:
washer.Wash((dynamic)x);
Ponieważ x jest następnie przekształcany do dynamicznego typu jego rzeczywisty typ zostaną zakwalifikowani do wysyłki i tak oba x oraz podkładka zostaną wykorzystane, aby wybrać właściwą metodę tak, że CarWasher.Wash (samochód) zostanie wywołany (sprawdzenie, że kod działa poprawnie i pozostanie intuicyjny).
Osobne struktury danych i operacje
Inną zaletą i wymogiem jest, że można go oddzielić od struktury danych operacji. Może to być zaletą, ponieważ pozwala dodawać nowych użytkowników, którzy mają własne operacje, a także umożliwia dodawanie struktur danych, które "dziedziczą" te operacje. Może być jednak zastosowany tylko wtedy, gdy ta seperacja może być wykonana/ma sens. Klasy, które wykonują operacje (użytkownicy) nie znają struktury danych ani nie muszą wiedzieć, co sprawia, że kod jest łatwiejszy do utrzymania i wielokrotnego użytku. Z tego powodu odwiedzający wykonują operacje dla różnych elementów w strukturach danych.
Załóżmy, że masz różne struktury danych i wszystkie składają się z elementów klasy Element. Struktury mogą być listy, stosy, drzewa, kolejki itp
można następnie wdrożyć odwiedzających że w tym przypadku będzie miał następującą metodę:
Visit(Item)
Struktury danych muszą przyjąć gości i wtedy nazywamy Odwiedź metodę dla każdej pozycji.
W ten sposób można wdrożyć wszelkiego rodzaju użytkowników i nadal można dodawać nowe struktury danych, o ile składają się one z elementów typu Element.
W przypadku bardziej szczegółowych struktur danych z dodatkowymi elementami (np. Węzłem) można rozważyć określonego użytkownika (NodeVisitor), który dziedziczy po zwykłym Goście i nowe struktury danych akceptują tego użytkownika (Accept (NodeVisitor)). Nowi użytkownicy mogą być wykorzystywani do nowych struktur danych, ale także do starych struktur danych z powodu dziedziczenia, więc nie trzeba modyfikować istniejącego "interfejsu" (w tym przypadku super klasy).
IMO przegapiłeś ważny punkt ... powinieneś ** NIGDY ** (I napiszę jeszcze większy) mają coś takiego jak "switch (type of obj)". Nie ma znaczenia, czy odwiedzający, czy nie. Jeśli twój kod nie jest taki, to nie napiszesz żadnego kodu standardowego. –
** Przykłady **, kiedy odwiedzający może Ci pomóc? Wyobraź sobie, że piszesz narzędzie do wyszukiwania tekstu w plikach. Wyszukiwarka odwiedza każdy element systemu plików (pliki będą odwiedzane, a katalogi będą propagować odwiedziny do każdego elementu podrzędnego). Elementy systemu plików mogą być katalogami, plikami, linkami do stron FTP ... wyszukiwarka nigdy nie będzie wiedzieć, co działa. Gość nie powinien znać dokładnego typu (nie z powodu wzoru gościa, ale z powodu zasad OOP ...) –
Odwiedzający są na zbyt niskim poziomie. Nie ma sensu korzystać z odwiedzających, gdy możesz zrobić coś takiego: http://www.cs.indiana.edu/~dyb/pubs/nano-jfp.pdf –