Różnice między wzorcem proxy i dekoratorem

144

Czy możesz podać jakieś dobre wyjaśnienie, jaka jest różnica między proxy a dekoratorem ?

Główną różnicą, którą widzę, jest to, że kiedy zakładamy, że proxy używa kompozycji, a dekorator używa agregacji , wydaje się jasne, że używając wielu (jednego lub więcej) dekoratorów można modyfikować / dodawać funkcje do wcześniej istniejącej instancji (dekorować), podczas gdy Proxy ma własne wewnętrzne wystąpienie klasy proxy i delegatów do niej dodających dodatkowe funkcje (zachowanie proxy).

Pytanie brzmi - czy proxy utworzone za pomocą agregacji jest nadal proxy, czy raczej dekoratorem ? Czy dozwolone jest (z definicji we wzorcach GoF) tworzenie proxy z agregacją?

Łukasz Rzeszotarski
źródło
2
Kilka linków: Proxy and Decorator
Sotirios Delimanolis
5
Skąd pomysł, że Proxy używa kompozycji, a Dekorator używa agregacji?
CPerkins
1
@CPerkins zobacz mój komentarz do odpowiedzi Rahul Tripathi.
Łukasz Rzeszotarski
1
A także dekorator ( patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - oczywiście agregacja, proxy ( patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - oczywiście skład.
hyankov

Odpowiedzi:

28

Oto bezpośredni cytat z GoF (strona 216).

Chociaż dekoratory mogą mieć podobne implementacje jak proxy, dekoratory mają inny cel. Dekorator dodaje jedną lub więcej obowiązków do obiektu, podczas gdy proxy kontroluje dostęp do obiektu.

Serwery proxy różnią się stopniem, w jakim są implementowane jak dekorator. Proxy ochrony można zaimplementować dokładnie tak, jak dekorator. Z drugiej strony, zdalny serwer proxy nie będzie zawierał bezpośredniego odniesienia do swojego rzeczywistego podmiotu, a jedynie odniesienie pośrednie, takie jak „identyfikator hosta i adres lokalny na hoście”. Wirtualny serwer proxy zacznie od pośredniego odniesienia, takiego jak nazwa pliku, ale ostatecznie uzyska i użyje bezpośredniego odniesienia.

Popularne odpowiedzi wskazują, że Pełnomocnik zna konkretny typ swojego pełnomocnika. Z tego cytatu widać, że nie zawsze jest to prawdą.

Różnica między proxy a dekoratorem według GoF polega na tym, że proxy ogranicza klienta. Dekorator tego nie robi. Proxy może ograniczyć to, co robi klient , kontrolując dostęp do funkcji; lub może ograniczyć to, co wie klient , wykonując czynności, które są dla niego niewidoczne i nieznane. Dekorator postępuje odwrotnie: wzmacnia to, co robi jego delegat, w sposób widoczny dla klientów.

Można powiedzieć, że proxy to czarne pudełko, a dekorator to białe pudełko.

Relacja kompozycyjna między opakowaniem a delegatem jest niewłaściwą relacją, na której należy się skupić, porównując proxy z dekoratorem, ponieważ kompozycja jest cechą wspólną tych dwóch wzorców. Relacja między opakowaniem a klientem jest tym, co odróżnia te dwa wzorce.

  • Dekorator informuje i wzmacnia swojego klienta.
  • Proxy ogranicza i wyłącza uprawnienia swojego klienta.
jaco0646
źródło
121

Prawdziwą różnicą nie jest własność (skład a agregacja), ale raczej informacja o typie.

Dekorator jest zawsze przeszedł przekazano. Proxy może go utworzyć sam, lub że może mieć on wstrzykiwany.

Ale Pełnomocnik zawsze zna (bardziej) konkretny typ delegata. Innymi słowy, proxy i jego delegat będą mieć ten sam typ podstawowy, ale proxy wskazuje na jakiś typ pochodny. Dekorator wskazuje na własnym typie bazowym. Zatem różnica polega na informacjach w czasie kompilacji o typie delegata.

W języku dynamicznym, jeśli delegat jest wstrzykiwany i ma ten sam interfejs, nie ma różnicy.

Odpowiedź na Twoje pytanie brzmi „Tak”.

cdunn2001
źródło
2
„Ale Pełnomocnik zawsze zna (bardziej) konkretny typ delegata.” Nie sądzę, że to prawda. Wyobraź sobie zdalne proxy. Mechanizm proxy nie musi znać żadnych szczegółów dotyczących zdalnego obiektu. System zdalny rejestruje obiekt za pomocą określonego interfejsu. Lokalny serwer proxy udostępnia ten sam interfejs.
Alexey
3
Wziąłem zajęcia na ten temat w Amazon od odwiedzającego wykładowcy, który znał się na rzeczy. Istnieje różnica między używaniem pliku wykonywalnego „proxy” (np. Z usługą internetową) a wzorcem projektowym proxy. UML wzorca proxy i wzorca dekoratora mogą być różne. Ale nic nie stoi na przeszkodzie, aby serwer proxy posiadał ten sam interfejs API, co jego delegat. Dekorator jest ścisłym podzbiorem proxy, ale dekorator może być nadal nazywany proxy w zależności od tego, czy podstawowy interfejs API jest gwarantowany .
cdunn2001
88

Wzorzec dekoratora skupia się na dynamicznym dodawaniu funkcji do obiektu, podczas gdy Wzorzec proxy skupia się na kontrolowaniu dostępu do obiektu.

EDYTOWAĆ:-

Relacja między serwerem proxy a rzeczywistym tematem jest zwykle ustawiana w czasie kompilacji, serwer proxy tworzy go w jakiś sposób, podczas gdy dekorator jest przypisywany do tematu w czasie wykonywania, znając tylko interfejs podmiotu.

Rahul Tripathi
źródło
5
Jednak nadal można używać serwera proxy do dodawania funkcji. Pomyśl o proxy AOP.
Sotirios Delimanolis
5
Całkowicie się zgadzam Sir. Innymi słowy, chciałbym przekonwertować to, co miałem na myśli, w przypadku wzoru proxy, klasa proxy może ukryć szczegółowe informacje o obiekcie przed klientem. Dlatego też, używając Wzorca Proxy, zazwyczaj tworzymy wystąpienie abject wewnątrz klasy proxy. Korzystając z wzorca dekoratora, zazwyczaj przekazujemy oryginalny obiekt jako parametr do konstruktora dekoratora.
Rahul Tripathi
W tym przypadku, gdy instancja jest „ukryta” w proxy, różnica jest dla mnie jasna (jak pisałem), jednak myślę, że często ludzie wywołują klasy proxy, które pobierają obiekt proxy, który został przekazany jako parametr konstruktora. W tym przypadku różnica w dodawaniu nowej funkcjonalności lub kontroli jest (bardzo) mała.
Łukasz Rzeszotarski
5
Relacja między serwerem proxy a rzeczywistym tematem jest zwykle ustawiana w czasie kompilacji, serwer proxy tworzy go w jakiś sposób, podczas gdy dekorator lub adapter są przypisywane do podmiotu w czasie wykonywania, znając tylko interfejs podmiotu. Mam nadzieję, że to ma sens !!! :)
Rahul Tripathi
1
Czy możesz dodać tę linię do swojej odpowiedzi.
Łukasz Rzeszotarski
50

Dekorator otrzymuje referencje dla dekorowanego obiektu (zwykle przez konstruktora), podczas gdy Proxy jest za to odpowiedzialny.

Proxy może w ogóle nie tworzyć instancji zawijającego obiektu (tak jak robi to ORM, aby zapobiec niepotrzebnemu dostępowi do bazy danych, jeśli nie są używane pola obiektów / metody pobierające), podczas gdy Dekorator zawsze utrzymuje łącze do rzeczywistej opakowanej instancji.

Serwer proxy zwykle używany przez frameworki do dodawania zabezpieczeń lub buforowania / lazowania i konstruowany przez framework (nie przez zwykłego programistę).

Dekorator jest zwykle używany do dodawania nowego zachowania do starych lub starszych klas przez samego programistę w oparciu o interfejs, a nie rzeczywistą klasę (więc działa na szerokiej gamie instancji interfejsu, Proxy jest wokół konkretnej klasy).

gavenkoa
źródło
24

Kluczowe różnice:

  1. Proxy zapewnia ten sam interfejs. Dekorator zapewnia ulepszony interfejs.
  2. Dekorator i Proxy mają różne cele, ale podobne struktury. Oba opisują, jak zapewnić poziom pośrednictwa do innego obiektu, a implementacje zachowują odniesienie do obiektu, do którego przekazują żądania.
  3. Dekorator może być postrzegany jako zdegenerowany kompozyt zawierający tylko jeden składnik. Jednak dekorator dodaje dodatkowe obowiązki - nie jest przeznaczony do agregacji obiektów.
  4. Dekorator obsługuje kompozycję rekurencyjną
  5. Dekorator klasa deklaruje skład relacji do LCD (najniższa klasa mianowniku) interfejs, i ten element danych jest inicjowany w jego konstruktora.
  6. Użyj proxy do leniwej inicjalizacji, poprawy wydajności poprzez buforowanie obiektu i kontrolowanie dostępu do klienta / dzwoniącego

Artykuł Sourcemaking znakomicie cytuje podobieństwa i różnice.

Powiązane pytania / linki dotyczące SE:

Kiedy używać wzoru dekoratora?

Jaka jest dokładna różnica między wzorcami adaptera i serwera proxy?

Ravindra babu
źródło
4

Proxy i Decorator różnią się przeznaczeniem i miejscem, w którym koncentrują się na wewnętrznej implementacji. Serwer proxy służy do korzystania ze zdalnego, wieloprocesowego lub międzysieciowego obiektu tak, jakby był obiektem lokalnym. Dekorator służy do dodawania nowego zachowania do oryginalnego interfejsu.

Chociaż oba wzorce mają podobną strukturę, większość złożoności Proxy polega na zapewnieniu właściwej komunikacji z obiektem źródłowym. Dekorator natomiast skupia się na implementacji dodanego zachowania.

James Lin
źródło
Co mówisz, co różni się od pozostałych 4 odpowiedzi już tutaj?
Stephen Rauch,
Nie wiem, czy to wszystko tam jest. Po przeczytaniu poprzednich odpowiedzi poczułem chęć, żeby się do tego zabrać.
James Lin,
1

Zajęło trochę czasu, zanim zrozumiałem odpowiedź i co to naprawdę oznacza. Kilka przykładów powinno wyjaśnić sprawę.

Proxy pierwszy:

public interface Authorization {
    String getToken();
} 

I :

// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
    @Override
    public String getToken() {
        return "DB-Token";
    }
}

I jest ten rozmówca Authorization, całkiem głupi:

class Caller {
    void authenticatedUserAction(Authorization authorization) {
        System.out.println("doing some action with : " + authorization.getToken());
    }
}

Na razie nic niezwykłego, prawda? Uzyskaj token z określonej usługi, użyj tego tokena. Teraz pojawia się jeszcze jedno wymaganie do obrazu, dodaj logowanie: co oznacza, że ​​loguj token za każdym razem. W tym przypadku jest to proste, po prostu utwórz Proxy:

public class LoggingDBAuthorization implements Authorization {

    private final DBAuthorization dbAuthorization = new DBAuthorization();

    @Override
    public String getToken() {
        String token = dbAuthorization.getToken();
        System.out.println("Got token : " + token);
        return token;
    }
}

Jak byśmy to wykorzystali?

public static void main(String[] args) {
    LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();

    Caller caller = new Caller();
    caller.authenticatedUserAction(loggingDBAuthorization);
}

Zauważ, że LoggingDBAuthorization zawiera wystąpienie DBAuthorization. Zarówno LoggingDBAuthorizationi DBAuthorization implementuj Authorization .

  • Serwer proxy będzie zawierał konkretną implementację ( DBAuthorization) interfejsu podstawowego ( Authorization). Innymi słowy, Pełnomocnik dokładnie wie , co jest przekazywane.

Decorator:

Zaczyna się prawie tak samo jak Proxyz interfejsem:

public interface JobSeeker {
    int interviewScore();
}

i jego wdrożenie:

class Newbie implements JobSeeker  {
    @Override
    public int interviewScore() {
        return 10;
    }
}

A teraz chcemy dodać bardziej doświadczonego kandydata, który dodaje wynik rozmowy kwalifikacyjnej plus jeden od drugiego JobSeeker:

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

    @Override
    public int interviewScore() {
        return jobSeeker.interviewScore() + 20;
    } 
}

Zwróć uwagę, jak powiedziałem to plus ten od innego Poszukiwacza pracy , nie Newbie . A Decoratornie wie dokładnie, co ozdabia, zna tylko kontrakt tej zdobionej instancji (o czym wie JobSeeker). Zwróć uwagę, że to nie jest podobne do Proxy; który z kolei dokładnie wie, co ozdabia.

Możesz zapytać, czy w tym przypadku jest jakaś różnica między tymi dwoma wzorcami projektowymi? A co by było, gdybyśmy spróbowali napisać Decoratorjako a Proxy?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

    @Override
    public int interviewScore() {
        return newbie.interviewScore() + 20;
    }
}

Jest to zdecydowanie opcja i podkreśla, jak bliskie są te wzorce; są one nadal przeznaczone dla różnych scenariuszy, jak wyjaśniono w innych odpowiedziach.

Eugene
źródło
0

Serwer proxy zapewnia ten sam interfejs dla opakowanego obiektu, dekorator zapewnia mu ulepszony interfejs, a serwer proxy zwykle samodzielnie zarządza cyklem życia obiektu usługi, podczas gdy skład dekoratorów jest zawsze kontrolowany przez klienta.

Ali Bayat
źródło