Patrzyłem na wzór proxy i wydaje mi się to okropnie podobne do wzorów Decorator, Adapter i Bridge. Czy coś nie rozumiem? Co za różnica? Dlaczego miałbym używać wzorca proxy w porównaniu do innych? Jak korzystałeś z nich w przeszłości w projektach z prawdziwego świata?
design-patterns
decorator
bridge
proxy-pattern
Charles Graham
źródło
źródło
Odpowiedzi:
Proxy, dekorator, adapter i mostek są odmianami „zawijania” klasy. Ale ich zastosowania są różne.
Proxy może być użyte, gdy chcesz leniwie utworzyć instancję obiektu lub ukryć fakt, że dzwonisz do usługi zdalnej lub kontrolować dostęp do obiektu.
Dekorator jest również nazywany „Smart Proxy”. Jest to używane, gdy chcesz dodać funkcjonalność do obiektu, ale nie przez rozszerzenie typu tego obiektu. To pozwala ci to zrobić w czasie wykonywania.
Adapter jest używany, gdy masz interfejs abstrakcyjny i chcesz zmapować ten interfejs na inny obiekt, który ma podobną rolę funkcjonalną, ale inny interfejs.
Bridge jest bardzo podobny do Adaptera, ale nazywamy go Bridge, gdy definiujesz zarówno interfejs abstrakcyjny, jak i podstawową implementację. Oznacza to, że nie dostosowujesz się do jakiegoś starszego kodu lub kodu innej firmy, jesteś projektantem całego kodu, ale musisz mieć możliwość wymiany różnych implementacji.
Fasada to interfejs wyższego poziomu (czytaj: prostszy) do podsystemu jednej lub więcej klas. Załóżmy, że masz złożoną koncepcję, która wymaga reprezentacji wielu obiektów. Wprowadzanie zmian w tym zestawie obiektów jest mylące, ponieważ nie zawsze wiesz, który obiekt ma metodę, którą musisz wywołać. Nadszedł czas, aby napisać fasadę, która zapewnia metody wysokiego poziomu dla wszystkich złożonych operacji, jakie można wykonać na zbiorze obiektów. Przykład: Domain Wzór sekcji szkolnej metod, takich jak
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
i tak dalej.źródło
Jak mówi odpowiedź Billa, ich przypadki użycia są różne .
Podobnie jak ich struktury.
Zarówno proxy, jak i dekorator mają taki sam interfejs, jak ich opakowane typy, ale proxy tworzy instancję pod maską, podczas gdy dekorator bierze instancję w konstruktorze.
Zarówno adapter, jak i fasada mają inny interfejs niż to, co obejmują. Ale adapter wywodzi się z istniejącego interfejsu, podczas gdy fasada tworzy nowy interfejs.
Mostek i adapter wskazują na istniejący typ. Ale most będzie wskazywał na typ abstrakcyjny, a adapter może wskazywać na konkretny typ. Mostek pozwoli ci sparować implementację w czasie wykonywania, podczas gdy adapter zwykle nie.
źródło
Moje zdanie na ten temat.
Wszystkie cztery wzorce mają ze sobą wiele wspólnego, wszystkie cztery są czasem nieformalnie nazywane opakowaniami lub wzorami opakowań. Wszyscy używają kompozycji, zawijania tematu i delegowania wykonania do tematu w pewnym momencie, odwzorowując jedno wywołanie metody na inne. Oszczędzają klientowi konieczności konstruowania innego obiektu i kopiowania wszystkich istotnych danych. Jeśli są używane mądrze, oszczędzają pamięć i procesor.
Promując luźne sprzęganie, sprawiają, że niegdyś stabilny kod jest mniej narażony na nieuniknione zmiany i lepiej czytelny dla innych programistów.
Adapter
Adapter dostosowuje temat (adapttee) do innego interfejsu. W ten sposób możemy dodać obiekt do zbioru nominalnie różnych typów.
Adapter udostępnia klientowi tylko odpowiednie metody, może ograniczyć wszystkie inne, ujawniając zamiary użytkowania w określonych kontekstach, takie jak adaptacja zewnętrznej biblioteki, sprawiając, że wydaje się ona mniej ogólna i bardziej skoncentrowana na potrzebach naszej aplikacji. Adaptery zwiększają czytelność i własny opis naszego kodu.
Adaptery chronią jeden zespół przed niestabilnym kodem od innych zespołów; narzędzie ratujące życie w kontaktach z zespołami offshore ;-)
Mniej wspomniany ma na celu zapobieganie nadmiarowi adnotacji w klasie przedmiotów. Przy tak wielu ramach opartych na adnotacjach staje się to ważniejsze niż kiedykolwiek.
Adapter pomaga ominąć ograniczenie Java tylko jednego dziedziczenia. Może łączyć kilka adapterów pod jedną kopertą, co daje wrażenie wielokrotnego dziedziczenia.
Pod względem kodu adapter jest „cienki”. Nie powinien dodawać zbyt wiele kodu do klasy adapttee, oprócz zwykłego wywoływania metody adapttee i sporadycznych konwersji danych niezbędnych do wykonywania takich wywołań.
W JDK lub bibliotekach podstawowych nie ma wielu dobrych przykładów adapterów. Twórcy aplikacji tworzą Adaptery, aby dostosować biblioteki do interfejsów specyficznych dla aplikacji.
Dekorator
Dekorator nie tylko deleguje, nie tylko mapuje jedną metodę na drugą, ale robi więcej, modyfikuje zachowanie niektórych metod przedmiotowych, może zdecydować, że w ogóle nie wywoła metody podmiotowej, deleguje do innego obiektu, obiektu pomocnika.
Dekoratorzy zazwyczaj dodają (przezroczystą) funkcjonalność do zawiniętego obiektu, taką jak rejestrowanie, szyfrowanie, formatowanie lub kompresja obiektu. Ta nowa funkcjonalność może przynieść wiele nowego kodu. Dlatego dekoratorzy są zwykle o wiele „grubsi” niż Adaptery.
Dekorator musi być podklasą interfejsu podmiotu. Można ich używać w sposób przejrzysty zamiast tematów. Patrz BufferedOutputStream, nadal jest OutputStream i może być używany jako taki. Jest to główna różnica techniczna w stosunku do adapterów.
Przykłady podręczników dla całej rodziny dekoratorów znajdują się w JDK - Java IO. Wszystkie klasy, takie jak BufferedOutputStream , FilterOutputStream i ObjectOutputStream, są dekoratorami OutputStream . Mogą być warstwami cebuli, gdzie jeden dekorator jest ponownie dekorowany, co zwiększa funkcjonalność.
Pełnomocnik
Serwer proxy nie jest typowym opakowaniem. Zawinięty obiekt, podmiot proxy, może jeszcze nie istnieć w momencie tworzenia proxy. Serwer proxy często tworzy go wewnętrznie. Może to być ciężki obiekt tworzony na żądanie lub obiekt zdalny w innej maszynie JVM lub w innym węźle sieciowym, a nawet obiekt inny niż Java, składnik w natywnym kodzie. Nie musi wcale owijać ani delegować do innego obiektu.
Najbardziej typowymi przykładami są zdalne proxy, inicjatory ciężkich obiektów i proxy dostępu.
Remote Proxy - podmiot znajduje się na zdalnym serwerze, innym JVM lub nawet w systemie innym niż Java. Serwer proxy tłumaczy wywołania metod na wywołania RMI / REST / SOAP lub cokolwiek jest potrzebne, chroniąc klienta przed narażeniem na podstawowe technologie.
Lazy Load Proxy - pełna inicjalizacja obiektu tylko przy pierwszym użyciu lub pierwszym intensywnym użyciu.
Access Proxy - kontroluj dostęp do tematu.
Fasada
Fasada jest ściśle związana z zasadą projektowania najmniejszej wiedzy (Law of Demeter). Fasada jest bardzo podobna do adaptera. Obaj się zawijają, oboje mapują jeden obiekt na inny, ale różnią się intencją. Fasada spłaszcza złożoną strukturę obiektu, złożony wykres obiektu, upraszczając dostęp do złożonej struktury.
Fasada otacza złożoną strukturę, zapewniając płaski interfejs. Zapobiega to narażeniu obiektu klienta na relacje wewnętrzne w strukturze podmiotu, a tym samym sprzyja luźnemu łączeniu.
Most
Bardziej złożony wariant wzorca adaptera, w którym różni się nie tylko implementacja, ale również abstrakcja. Dodaje jeszcze jedno pośrednie przekazanie uprawnień. Dodatkowa delegacja to most. Oddziela adapter nawet od dostosowania interfejsu. Zwiększa złożoność bardziej niż jakikolwiek inny wzór owijania, więc aplikuj ostrożnie.
Różnice w konstruktorach
Różnice w strukturze są również widoczne, gdy patrzymy na ich konstruktorów.
Serwer proxy nie zawija istniejącego obiektu. Konstruktor nie zawiera tematu.
Dekorator i adapter owijają już istniejący obiekt, i taki jest zwykle
dostarczany w konstruktorze.
Konstruktor fasad pobiera element główny z wykresu całego obiektu, w przeciwnym razie wygląda tak samo jak Adapter.
Przykład z życia - adapter Marshalling JAXB . Celem tego adaptera jest odwzorowanie prostej klasy płaskiej na bardziej złożoną strukturę wymaganą zewnętrznie i zapobieganie „zanieczyszczeniu” klasy przedmiotu za pomocą nadmiernych adnotacji.
źródło
Wiele wzorców GoF nakłada się na siebie. Wszystkie są zbudowane na sile polimorfizmu i czasami naprawdę różnią się tylko intencją. (strategia vs. stan)
Moje zrozumienie wzorów wzrosło 100-krotnie po przeczytaniu Head First Design Patterns .
Gorąco polecam!
źródło
Wszystkie dobre odpowiedzi ekspertów wyjaśniły już, co oznacza każdy wzór.
Będę ozdobić kluczowych punktów.
Dekorator:
na przykład (z łańcuchowym):
java.io
zajęcia związane z pakietówInputStream
iOutputStream
interfejsówPełnomocnik:
np .:
java.rmi
klasy pakietów.Adapter:
np.
java.io.InputStreamReader
(InputStream
zwraca aReader
)Most:
np. klasy kolekcji w
java.util
.List
realizowane przezArrayList
.Kluczowe uwagi:
Rzuć okiem na świetne pytania / artykuły dotyczące SE dotyczące przykładów różnych wzorców projektowych
Kiedy stosować wzór dekoratora?
Kiedy używasz wzorca mostu? Czym różni się od wzorca adaptera?
Różnice między wzorem proxy a dekoratorem
źródło
Są dość podobne, a linie między nimi są dość szare. Sugeruję przeczytanie wpisów Wzorca proxy i Wzorca dekoratora na wiki wiki c2.
Wpisy i dyskusje są dość obszerne, a także zawierają linki do innych odpowiednich artykułów. Nawiasem mówiąc, wiki c2 jest doskonała, gdy zastanawiasz się nad niuansami między różnymi wzorami.
Podsumowując wpisy C2, powiedziałbym, że dekorator dodaje / zmienia zachowanie, ale proxy ma więcej wspólnego z kontrolą dostępu (leniwa instancja, zdalny dostęp, bezpieczeństwo itp.). Ale, jak powiedziałem, linie między nimi są szare i widzę odniesienia do serwerów proxy, które można łatwo postrzegać jako dekoratorów i odwrotnie.
źródło
Wszystkie cztery wzory wymagają zawijania wewnętrznego obiektu / klasy zewnętrznym, więc są bardzo podobne strukturalnie. Chciałbym przedstawić różnicę według celu:
I przez zmianę interfejsu między obiektami wewnętrznymi i zewnętrznymi:
źródło
To jest cytat z Head First Design Patterns
Definicje należą do książki. Przykłady należą do mnie.
Dekorator - nie zmienia interfejsu, ale dodaje odpowiedzialność. Załóżmy, że masz interfejs samochodu. Po wdrożeniu tego dla innego modelu samochodu (s, sv, sl) może być konieczne dodanie większej odpowiedzialności za niektóre modele. Podobnie jak szyberdach, poduszka powietrzna itp.
Adapter - Konwertuje jeden interfejs na inny. Masz interfejs samochodu i chciałbyś, aby działał jak jeep. Więc weź samochód, zmodyfikuj go i zamień w jeepa. Ponieważ nie jest to prawdziwy jeep. Ale działa jak jeep.
Fasada - upraszcza interfejs. Załóżmy, że masz interfejs samochodu, samolotu i statku. Właściwie wszystko, czego potrzebujesz, to klasa, która wysyła ludzi z jednej lokalizacji do drugiej. Chcesz, aby fasada decydowała, jakiego pojazdu użyć. Następnie zbierasz wszystkie odniesienia do interfejsów pod 1 parasolem i pozwalasz decydować / delegować, aby było to proste.
Po pierwsze: „Fasada nie tylko upraszcza interfejs, ale także oddziela klienta od podsystemu komponentów. Fasady i adaptery mogą owijać wiele klas, ale intencją fasady jest uproszczenie, podczas gdy adapter ma przekonwertować interfejs na coś innego. „
źródło
Używam go dość często podczas korzystania z usług internetowych. Nazwa wzoru proxy powinna prawdopodobnie zostać przemianowana na coś bardziej pragmatycznego, na przykład „Wzorzec opakowania”. Mam również bibliotekę, która jest serwerem proxy do MS Excel. Ułatwia to automatyzację programu Excel, bez martwienia się o szczegóły tła, takie jak wersja jest zainstalowana (jeśli istnieje).
źródło
Mówiąc szczegółowo o implementacji, widzę różnicę między serwerem proxy a dekoratorem, adapterem, fasadą ... We wspólnej implementacji tych wzorów istnieje obiekt docelowy owinięty otaczającym obiektem. Klient używa obiektu otaczającego zamiast obiektu docelowego. Obiekt docelowy faktycznie odgrywa ważną rolę w niektórych metodach zamykania obiektu.
Jednak w przypadku serwera proxy otaczający obiekt może sam odtwarzać niektóre metody, po prostu inicjuje obiekt docelowy, gdy klient wywołuje metody, w których musi brać udział obiekt docelowy. Jest to leniwa inicjalizacja. W przypadku innych wzorów otaczanie obiektu jest praktycznie oparte na obiekcie docelowym. Tak więc obiekt docelowy jest zawsze inicjowany wraz z otaczaniem obiektu w konstruktorach / ustawieniach.
Inną rzeczą jest to, że serwer proxy robi dokładnie to samo, co cel, podczas gdy inne wzorce zwiększają funkcjonalność celu.
źródło
Chciałbym dodać przykłady do odpowiedzi Billa Karwinga (co jest świetne przy okazji). Dodam także kilka kluczowych różnic w implementacji, które moim zdaniem brakuje.
Cytowane części pochodzą z odpowiedzi [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)
ProxyClass i ObjectClass, które są proxy, powinny implementować ten sam interfejs, więc można je zamieniać
Przykład - kosztowny obiekt proxy
DecoratorClass powinien (mógł) implementować rozszerzony interfejs ObjectClass. Zatem ObjectClass można zastąpić DecoratorClass, ale nie odwrotnie.
Przykład - dodanie funkcji dodawania
Różnice w implantacji Proxy, dekorator, adapter
Adapter zapewnia inny interfejs dla swojego tematu. Serwer proxy zapewnia ten sam interfejs. Decorator zapewnia ulepszony interfejs.
Większość informacji w tej odpowiedzi pochodzi z https://sourcemaking.com/design_patterns , które polecam jako doskonałe źródło wzorców projektowych.
źródło
Wierzę, że kod da jasne pomysły (w celu uzupełnienia innych odpowiedzi). Zobacz poniżej (Skoncentruj typy, które klasa implementuje i pakuje)
źródło
Wzorzec projektowy to nie matematyka, to połączenie sztuki i inżynierii oprogramowania. Nie ma nic takiego jak w przypadku tego wymagania, musisz użyć proxy, mostu itp. Wzory projektowe są tworzone w celu rozwiązania problemów. Jeśli przewidujesz problem z projektem, użyj go. Na podstawie doświadczenia poznasz konkretny problem, którego wzoru użyć. Jeśli jesteś dobry w solidnych zasadach projektowania, zaimplementowałbyś wzór projektowy, nie wiedząc, że jest to wzór. Typowym przykładem są wzorce statergy i fabryczne
Dlatego skoncentruj się bardziej na zasadach solidnego projektowania, zasad czystego kodowania i ttd
źródło