Unterschiede zwischen Proxy- und Decorator-Muster

135

Können Sie eine gute Erklärung geben, was der Unterschied zwischen Proxy und Decorator ist ?

Der wesentliche Unterschied ich sehe , ist , dass , wenn wir davon ausgehen , dass Proxy verwendet Zusammensetzung und Dekorateur Verwendungen Aggregation dann scheint es klar zu sein , dass durch mehrfache Verwendung von (einem oder mehreren) Dekorateure Sie können Funktionalitäten ändern / hinzufügen Instanz (deco) zu dem bereits bestehenden, während Der Proxy verfügt über eine eigene innere Instanz der Proxy-Klasse und delegiert diese mit zusätzlichen Funktionen (Proxy-Verhalten).

Die Frage ist: Ist der mit Aggregation erstellte Proxy immer noch Proxy oder eher Decorator ? Darf (per Definition in GoF-Mustern) ein Proxy mit Aggregation erstellt werden?

Łukasz Rzeszotarski
quelle
2
Einige Links: Proxy und Dekorateur
Sotirios Delimanolis
5
Woher kam die Idee, dass Proxy Komposition und Decorator Aggregation verwendet?
CPerkins
1
@ CPerkins siehe meinen Kommentar für Rahul Tripathi Antwort.
Łukasz Rzeszotarski
@CPerkins, ich stimme ŁukaszRzeszotarski zu - ein Proxy ist ein Proxy (und kein Dekorateur) im klassischen Sinne von "Proxy", nur wenn er Komposition verwendet. Wenn der Proxy über Aggregation auf die reale Klasse verweisen würde, wäre er ein Decorator! Ich wünschte, ich könnte Ihren Kommentar ablehnen. Auch dies - stackoverflow.com/questions/885937/…
Hyankov
1
Und auch Dekorateur ( patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - offensichtlich Aggregation, Proxy ( patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - offensichtlich Zusammensetzung.
Hyankov

Antworten:

15

Hier ist das direkte Zitat aus dem GoF (Seite 216).

Obwohl Dekorateure ähnliche Implementierungen wie Proxys haben können, haben Dekorateure einen anderen Zweck. Ein Dekorateur fügt einem Objekt eine oder mehrere Verantwortlichkeiten hinzu, während ein Proxy den Zugriff auf ein Objekt steuert.

Proxies unterscheiden sich in dem Grad, in dem sie wie ein Dekorateur implementiert werden. Ein Schutz-Proxy kann genau wie ein Dekorateur implementiert werden. Andererseits enthält ein Remote-Proxy keinen direkten Verweis auf sein eigentliches Subjekt, sondern nur einen indirekten Verweis wie "Host-ID und lokale Adresse auf dem Host". Ein virtueller Proxy beginnt mit einer indirekten Referenz wie einem Dateinamen, erhält und verwendet jedoch möglicherweise eine direkte Referenz.

Beliebte Antworten weisen darauf hin, dass ein Proxy den konkreten Typ seines Delegaten kennt. Aus diesem Zitat können wir erkennen, dass dies nicht immer der Fall ist.

Der Unterschied zwischen Proxy und Decorator gemäß GoF besteht darin, dass Proxy den Client einschränkt . Dekorateur nicht. Proxy kann beschränken , was ein Client tut durch Zugriff auf Funktionen zu steuern; oder es kann einschränken, was ein Client weiß, indem Aktionen ausgeführt werden, die für den Client unsichtbar und unbekannt sind. Decorator macht das Gegenteil: Es verbessert das, was sein Delegierter tut, auf eine Weise, die für Kunden sichtbar ist.

Wir könnten sagen, dass Proxy eine Black Box ist, während Decorator eine White Box ist.

Die Kompositionsbeziehung zwischen Wrapper und Delegat ist die falsche Beziehung, auf die Sie sich konzentrieren müssen, wenn Sie Proxy mit Decorator kontrastieren, da die Komposition das Merkmal ist, das diese beiden Muster gemeinsam haben. Die Beziehung zwischen Wrapper und Client unterscheidet diese beiden Muster.

  • Der Dekorateur informiert und befähigt seinen Kunden.
  • Proxy schränkt seinen Client ein und entmachtet ihn.
jaco0646
quelle
112

Der wirkliche Unterschied ist nicht das Eigentum (Zusammensetzung versus Aggregation), sondern die Typinformation.

Ein Dekorateur wird immer an seinen Delegierten übergeben. Ein Proxy könnte es selbst schaffen, oder er könnte haben es injiziert.

Ein Proxy kennt jedoch immer den (spezifischeren) Typ des Delegierten. Mit anderen Worten, der Proxy und sein Delegierter haben denselben Basistyp, aber der Proxy zeigt auf einen abgeleiteten Typ. Ein Dekorateur zeigt auf seinen eigenen Basistyp. Der Unterschied besteht also in den Informationen zur Kompilierungszeit über den Typ des Delegierten.

In einer dynamischen Sprache gibt es keinen Unterschied, wenn der Delegierte injiziert wird und zufällig dieselbe Schnittstelle hat.

Die Antwort auf Ihre Frage lautet "Ja".

cdunn2001
quelle
2
„Aber ein Proxy kennt immer den (spezifischeren) Typ des Delegierten.“ Ich denke nicht, dass es wahr ist. Stellen Sie sich einen Remote-Proxy vor. Der Proxy-Mechanismus muss keine Besonderheiten des Remote-Objekts kennen. Das ferne System registriert das Objekt bei der angegebenen Schnittstelle. Der lokale Proxy stellt dieselbe Schnittstelle bereit.
Alexey
3
Ich habe bei Amazon einen Kurs darüber von einem Gastdozenten besucht, der sich mit seinen Sachen auskannte. Es gibt einen Unterschied zwischen der Verwendung einer ausführbaren "Proxy" -Datei (z. B. mit einem Webdienst) und dem Proxy-Entwurfsmuster. Die UMLs des Proxy-Musters und des Decorator-Musters können unterschiedlich sein. Nichts hindert einen Proxy jedoch daran, dieselbe API wie sein Delegierter zu haben. Decorator ist eine strikte Teilmenge von Proxy. Ein Decorator kann jedoch weiterhin als Proxy bezeichnet werden, je nachdem, ob die zugrunde liegende API garantiert identisch ist.
cdunn2001
84

Das Dekorationsmuster konzentriert sich auf das dynamische Hinzufügen von Funktionen zu einem Objekt, während sich das Proxy- Muster auf die Steuerung des Zugriffs auf ein Objekt konzentriert.

BEARBEITEN:-

Die Beziehung zwischen einem Proxy und dem realen Betreff wird normalerweise zur Kompilierungszeit festgelegt. Der Proxy instanziiert sie auf irgendeine Weise, während Decorator dem Betreff zur Laufzeit zugewiesen wird und nur die Benutzeroberfläche des Betreffs kennt.

Rahul Tripathi
quelle
5
Ein Proxy kann jedoch weiterhin zum Hinzufügen von Funktionen verwendet werden. Denken Sie an AOP-Proxys.
Sotirios Delimanolis
5
Stimmen Sie voll und ganz zu, Sir. Ich würde das mit anderen Worten konvertieren, was ich mit Proxy-Muster gemeint habe. Die Proxy-Klasse kann die Detailinformationen eines Objekts vor ihrem Client verbergen. Daher erstellen wir bei Verwendung von Proxy Pattern normalerweise eine Instanz von abject innerhalb der Proxy-Klasse. Bei Verwendung von Decorator Pattern übergeben wir normalerweise das ursprüngliche Objekt als Parameter an den Konstruktor des Decorators.
Rahul Tripathi
In diesem Fall, wenn die Instanz im Proxy 'versteckt' ist, ist der Unterschied für mich klar (wie ich geschrieben habe), aber ich denke, dass Leute oft als Proxy-Klassen aufrufen, die das Proxy-Objekt verwenden, das als Konstruktorparameter übergeben wurde. In diesem Fall ist der Unterschied zwischen dem Hinzufügen neuer Funktionen oder dem Steuern für mich (sehr) gering.
Łukasz Rzeszotarski
5
Die Beziehung zwischen einem Proxy und dem realen Betreff wird normalerweise zur Kompilierungszeit festgelegt. Der Proxy instanziiert sie auf irgendeine Weise, während Decorator oder Adapter dem Betreff zur Laufzeit zugewiesen werden und nur die Benutzeroberfläche des Betreffs kennen. Hoffe das macht Sinn !!! :)
Rahul Tripathi
1
Sie können diese Zeile zu Ihrer Antwort hinzufügen.
Łukasz Rzeszotarski
49

Der Dekorateur erhält eine Referenz für das dekorierte Objekt (normalerweise durch den Konstrukteur), während der Proxy dafür verantwortlich ist.

Der Proxy instanziiert möglicherweise überhaupt kein Wrapping-Objekt (wie dies bei ORMs der Fall ist, um unnötigen Zugriff auf die Datenbank zu verhindern, wenn keine Objektfelder / Getter verwendet werden), während Decorator immer die Verknüpfung zur tatsächlich umhüllten Instanz hält.

Proxy, der normalerweise von Frameworks zum Hinzufügen von Sicherheit oder zum Zwischenspeichern / Löschen verwendet wird und vom Framework erstellt wird (nicht vom regulären Entwickler selbst).

Decorator wird normalerweise verwendet, um alten oder älteren Klassen vom Entwickler selbst neues Verhalten hinzuzufügen, basierend auf der Schnittstelle und nicht auf der tatsächlichen Klasse (daher funktioniert es bei einer Vielzahl von Schnittstelleninstanzen, Proxy handelt von konkreten Klassen).

Gavenkoa
quelle
22

Hauptunterschiede:

  1. Proxy bietet die gleiche Schnittstelle. Decorator bietet eine erweiterte Oberfläche.
  2. Decorator und Proxy haben unterschiedliche Zwecke, aber ähnliche Strukturen. Beide beschreiben, wie eine Indirektionsebene für ein anderes Objekt bereitgestellt wird, und die Implementierungen behalten einen Verweis auf das Objekt bei, an das sie Anforderungen weiterleiten.
  3. Decorator kann als entartetes Composite mit nur einer Komponente angesehen werden. Ein Decorator fügt jedoch zusätzliche Verantwortlichkeiten hinzu - er ist nicht für die Objektaggregation vorgesehen.
  4. Decorator unterstützt die rekursive Komposition
  5. Die Decorator- Klasse deklariert eine Zusammensetzungsbeziehung zur LCD-Schnittstelle (Lowest Class Denominator), und dieses Datenelement wird in seinem Konstruktor initialisiert.
  6. Verwenden Sie Proxy für eine verzögerte Initialisierung, Leistungsverbesserung durch Zwischenspeichern des Objekts und Steuern des Zugriffs auf den Client / Anrufer

Der Artikel über die Herstellung von Quellen zitiert die Ähnlichkeiten und Unterschiede auf hervorragende Weise.

Verwandte SE Fragen / Links:

Wann sollte das Dekorationsmuster verwendet werden?

Was ist der genaue Unterschied zwischen Adapter- und Proxy-Mustern?

Ravindra Babu
quelle
3

Proxy und Decorator unterscheiden sich in ihrem Zweck und wo sie sich auf die interne Implementierung konzentrieren. Proxy dient zur Verwendung eines Remote-, prozess- oder netzwerkübergreifenden Objekts, als wäre es ein lokales Objekt. Decorator dient zum Hinzufügen eines neuen Verhaltens zur ursprünglichen Benutzeroberfläche.

Während beide Muster in ihrer Struktur ähnlich sind, liegt der Hauptteil der Komplexität von Proxy darin, eine ordnungsgemäße Kommunikation mit dem Quellobjekt sicherzustellen. Decorator hingegen konzentriert sich auf die Implementierung des hinzugefügten Verhaltens.

James Lin
quelle
Was sagen Sie, das sich von den anderen 4 Antworten hier bereits unterscheidet?
Stephen Rauch
Ich weiß nicht, ob alles da ist. Ich hatte nur das Bedürfnis, mich einzuschalten, nachdem ich die vorherigen Antworten gelesen hatte.
James Lin
1

Es hat eine Weile gedauert, um diese Antwort herauszufinden und was sie wirklich bedeutet. Einige Beispiele sollen es klarer machen.

Proxy zuerst:

public interface Authorization {
    String getToken();
} 

Und :

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

Und es gibt einen Anrufer davon Authorization, einen ziemlich dummen:

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

Bisher nichts Ungewöhnliches, oder? Beziehen Sie ein Token von einem bestimmten Dienst und verwenden Sie dieses Token. Jetzt kommt eine weitere Anforderung an das Bild: Fügen Sie die Protokollierung hinzu: Das heißt, Sie protokollieren das Token jedes Mal. In diesem Fall ist es einfach: Erstellen Sie einfach Folgendes 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;
    }
}

Wie würden wir das nutzen?

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

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

Beachten Sie, dass LoggingDBAuthorization hält eine Instanz DBAuthorization. Beides LoggingDBAuthorizationund DBAuthorization implementieren Authorization .

  • Ein Proxy enthält eine konkrete Implementierung ( DBAuthorization) der Basisschnittstelle ( Authorization). Mit anderen Worten, ein Proxy weiß genau, was Proxy ist.

Decorator::

Es beginnt fast genauso wie Proxymit einer Schnittstelle:

public interface JobSeeker {
    int interviewScore();
}

und eine Implementierung davon:

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

Und jetzt möchten wir einen erfahreneren Kandidaten hinzufügen, der die Interview-Punktzahl plus die eines anderen hinzufügt JobSeeker:

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

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

Beachten Sie, wie ich das gesagt habe, plus das von einem anderen JobSeeker , nicht Newbie . A Decoratorweiß nicht genau, was es dekoriert, es kennt nur den Vertrag dieser dekorierten Instanz (es weiß davon JobSeeker). Beachten Sie hier, dass dies anders ist als ein Proxy; das weiß dagegen genau, was es dekoriert.

Sie könnten sich fragen, ob es in diesem Fall tatsächlich einen Unterschied zwischen den beiden Entwurfsmustern gibt? Was wäre, wenn wir versuchen würden, das Decoratorals zu schreiben Proxy?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

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

Dies ist definitiv eine Option und zeigt, wie nahe diese Muster sind. Sie sind weiterhin für verschiedene Szenarien vorgesehen, wie in den anderen Antworten erläutert.

Eugene
quelle
1

Proxy bietet dieselbe Schnittstelle für das umschlossene Objekt, Decorator bietet ihm eine erweiterte Schnittstelle und Proxy verwaltet normalerweise den Lebenszyklus seines Serviceobjekts selbst, während die Zusammensetzung der Decorators immer vom Client gesteuert wird.

Ali Bayat
quelle