Ich habe mir das Proxy-Muster angesehen, und für mich scheint es den Mustern Decorator, Adapter und Bridge sehr ähnlich zu sein. Verstehe ich etwas falsch? Was ist der Unterschied? Warum sollte ich das Proxy-Muster im Vergleich zu den anderen verwenden? Wie haben Sie sie in der Vergangenheit in realen Projekten eingesetzt?
design-patterns
decorator
bridge
proxy-pattern
Charles Graham
quelle
quelle
Antworten:
Proxy, Decorator, Adapter und Bridge sind Variationen beim "Umschließen" einer Klasse. Ihre Verwendung ist jedoch unterschiedlich.
Proxy kann verwendet werden, wenn Sie ein Objekt verzögert instanziieren oder die Tatsache verbergen möchten, dass Sie einen Remotedienst aufrufen, oder den Zugriff auf das Objekt steuern möchten.
Decorator wird auch als "Smart Proxy" bezeichnet. Dies wird verwendet, wenn Sie einem Objekt Funktionen hinzufügen möchten, jedoch nicht, indem Sie den Typ dieses Objekts erweitern. Dies ermöglicht Ihnen dies zur Laufzeit.
Der Adapter wird verwendet, wenn Sie eine abstrakte Schnittstelle haben und diese Schnittstelle einem anderen Objekt zuordnen möchten, das eine ähnliche funktionale Rolle, aber eine andere Schnittstelle hat.
Bridge ist Adapter sehr ähnlich, aber wir nennen es Bridge, wenn Sie sowohl die abstrakte Schnittstelle als auch die zugrunde liegende Implementierung definieren. Das heißt, Sie passen sich nicht an Legacy- oder Code von Drittanbietern an, Sie sind der Designer des gesamten Codes, aber Sie müssen in der Lage sein, verschiedene Implementierungen auszutauschen.
Facade ist eine übergeordnete (sprich: einfachere) Schnittstelle zu einem Subsystem einer oder mehrerer Klassen. Angenommen, Sie haben ein komplexes Konzept, für dessen Darstellung mehrere Objekte erforderlich sind. Das Vornehmen von Änderungen an dieser Gruppe von Objekten ist verwirrend, da Sie nicht immer wissen, welches Objekt die Methode hat, die Sie aufrufen müssen. Dies ist die Zeit, um eine Fassade zu schreiben, die allgemeine Methoden für alle komplexen Vorgänge bietet, die Sie für die Sammlung von Objekten ausführen können. Beispiel: Ein Domain Model für eine Schule Abschnitt, mit Methoden wie
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
, und so weiter.quelle
Wie Bills Antwort sagt, sind ihre Anwendungsfälle unterschiedlich .
So sind ihre Strukturen.
Proxy und Decorator haben beide dieselbe Schnittstelle wie ihre umschlossenen Typen, aber der Proxy erstellt eine Instanz unter der Haube, während der Decorator eine Instanz im Konstruktor übernimmt.
Adapter und Fassade haben beide eine andere Oberfläche als das, was sie einwickeln. Der Adapter leitet sich jedoch von einer vorhandenen Schnittstelle ab, während die Fassade eine neue Schnittstelle erstellt.
Bridge und Adapter zeigen beide auf einen vorhandenen Typ. Die Brücke zeigt jedoch auf einen abstrakten Typ, und der Adapter zeigt möglicherweise auf einen konkreten Typ. Über die Bridge können Sie die Implementierung zur Laufzeit koppeln, während dies beim Adapter normalerweise nicht der Fall ist.
quelle
Meine Sicht auf das Thema.
Alle vier Muster haben viel gemeinsam, alle vier werden manchmal informell als Wrapper oder Wrapper-Muster bezeichnet. Alle verwenden Komposition, umbrechen den Betreff und delegieren die Ausführung irgendwann an den Betreff. Ordnen Sie einen Methodenaufruf einem anderen zu. Sie ersparen dem Kunden die Notwendigkeit, ein anderes Objekt erstellen und alle relevanten Daten kopieren zu müssen. Mit Bedacht sparen sie Speicher und Prozessor.
Durch die Förderung der losen Kopplung wird der einst stabile Code weniger unvermeidlichen Änderungen ausgesetzt und für andere Entwickler besser lesbar.
Adapter
Der Adapter passt das Subjekt (Adaptee) an eine andere Schnittstelle an. Auf diese Weise können wir Objekte hinzufügen, die einer Sammlung von nominell unterschiedlichen Typen hinzugefügt werden sollen.
Der Adapter stellt dem Client nur relevante Methoden zur Verfügung, kann alle anderen einschränken und Verwendungsabsichten für bestimmte Kontexte offenlegen, z. B. die Anpassung der externen Bibliothek, und lässt sie weniger allgemein und stärker auf unsere Anwendungsanforderungen ausgerichtet erscheinen. Adapter verbessern die Lesbarkeit und Selbstbeschreibung unseres Codes.
Adapter schützen ein Team vor flüchtigem Code anderer Teams. ein lebensrettendes Werkzeug im Umgang mit Offshore-Teams ;-)
Weniger erwähnt dient es dazu, zu verhindern, dass die Fachklasse die Anmerkungen überschreitet. Bei so vielen Frameworks, die auf Anmerkungen basieren, wird diese Verwendung wichtiger als je zuvor.
Der Adapter hilft dabei, die Java-Beschränkung nur einer einzelnen Vererbung zu umgehen. Es kann mehrere Adaptees unter einem Umschlag kombinieren, was den Eindruck einer Mehrfachvererbung erweckt.
Code weise ist der Adapter "dünn". Es sollte der adaptee-Klasse nicht viel Code hinzufügen, außer einfach die adaptee-Methode aufzurufen und gelegentlich Datenkonvertierungen durchzuführen, die für solche Aufrufe erforderlich sind.
Es gibt nicht viele gute Adapterbeispiele in JDK oder Basisbibliotheken. Anwendungsentwickler erstellen Adapter, um Bibliotheken an anwendungsspezifische Schnittstellen anzupassen.
Dekorateur
Decorator delegiert nicht nur, ordnet nicht nur eine Methode einer anderen zu, sie tun mehr, sie ändern das Verhalten einiger Subjektmethoden, es kann entscheiden, überhaupt keine Subjektmethode aufzurufen, an ein anderes Objekt zu delegieren, ein Hilfsobjekt.
Dekorateure fügen verpackten Objekten normalerweise (transparent) Funktionen wie Protokollierung, Verschlüsselung, Formatierung oder Komprimierung des Betreffs hinzu. Diese neue Funktionalität kann viel neuen Code bringen. Daher sind Dekorateure normalerweise viel „dicker“ als Adapter.
Der Dekorateur muss eine Unterklasse der Benutzeroberfläche des Subjekts sein. Sie können transparent anstelle der Themen verwendet werden. Siehe BufferedOutputStream, es ist immer noch OutputStream und kann als solches verwendet werden. Das ist ein großer technischer Unterschied zu Adaptern.
Lehrbuchbeispiele der gesamten Dekorateurfamilie sind in JDK - dem Java IO - leicht zu finden. Alle Klassen wie BufferedOutputStream , FilterOutputStream und ObjectOutputStream sind Dekoratoren von OutputStream . Sie können mit Zwiebeln überzogen werden, wobei ein Dekorateur erneut dekoriert wird, wodurch mehr Funktionalität hinzugefügt wird.
Proxy
Proxy ist kein typischer Wrapper. Das umschlossene Objekt, das Proxy-Subjekt, ist zum Zeitpunkt der Proxy-Erstellung möglicherweise noch nicht vorhanden. Proxy erstellt es häufig intern. Es kann sich um ein schweres Objekt handeln, das bei Bedarf erstellt wird, oder es handelt sich um ein Remote-Objekt in einer anderen JVM oder einem anderen Netzwerkknoten und sogar um ein Nicht-Java-Objekt, eine Komponente im nativen Code. Es muss überhaupt nicht umbrochen oder an ein anderes Objekt delegiert werden.
Die typischsten Beispiele sind Remote-Proxys, Initialisierer für schwere Objekte und Zugriffsproxys.
Remote-Proxy - Betreff befindet sich auf einem Remote-Server, einer anderen JVM oder sogar einem Nicht-Java-System. Proxy übersetzt Methodenaufrufe in RMI / REST / SOAP-Aufrufe oder was auch immer erforderlich ist, um den Client vor dem Kontakt mit der zugrunde liegenden Technologie zu schützen.
Lazy Load Proxy - Initialisieren Sie das Objekt nur bei der ersten oder ersten intensiven Nutzung vollständig.
Access Proxy - Kontrolliert den Zugriff auf den Betreff.
Fassade
Die Fassade ist eng mit dem Gestaltungsprinzip des geringsten Wissens (Gesetz des Demeters) verbunden. Fassade ist Adapter sehr ähnlich. Sie wickeln beide ein, sie ordnen ein Objekt einem anderen zu, aber sie unterscheiden sich in der Absicht. Die Fassade glättet die komplexe Struktur eines Subjekts und das komplexe Objektdiagramm und vereinfacht den Zugriff auf eine komplexe Struktur.
Die Fassade umhüllt eine komplexe Struktur und bietet eine flache Schnittstelle. Dies verhindert, dass das Client-Objekt inneren Beziehungen in der Subjektstruktur ausgesetzt wird, wodurch eine lose Kopplung gefördert wird.
Brücke
Komplexere Variante des Adaptermusters, bei der nicht nur die Implementierung variiert, sondern auch die Abstraktion. Es fügt der Delegation eine weitere Indirektion hinzu. Die zusätzliche Delegation ist die Brücke. Es entkoppelt den Adapter sogar von der Anpassung der Schnittstelle. Es erhöht die Komplexität mehr als jedes andere Verpackungsmuster. Wenden Sie es daher mit Vorsicht an.
Unterschiede in den Konstruktoren
Musterunterschiede sind auch bei der Betrachtung ihrer Konstruktoren offensichtlich.
Der Proxy umschließt kein vorhandenes Objekt. Es gibt kein Thema im Konstruktor.
Decorator und Adapter umschließen bereits vorhandene Objekte, und diese werden normalerweise
im Konstruktor bereitgestellt.
Der Fassadenkonstruktor verwendet das Stammelement eines gesamten Objektdiagramms, ansonsten sieht es genauso aus wie der Adapter.
Beispiel aus dem wirklichen Leben - JAXB Marshalling Adapter . Zweck dieses Adapters ist die Zuordnung einer einfachen flachen Klasse zu einer komplexeren Struktur, die extern erforderlich ist, und um zu verhindern, dass die Subjektklasse mit übermäßigen Anmerkungen "verschmutzt" wird.
quelle
Viele der GoF-Muster überschneiden sich stark. Sie alle bauen auf der Kraft des Polymorphismus auf und unterscheiden sich manchmal nur in ihrer Absicht. (Strategie gegen Staat)
Mein Verständnis von Mustern hat sich nach dem Lesen von Head First Design Patterns um das 100-fache erhöht .
Ich empfehle es sehr!
quelle
Alle guten Antworten von Experten haben bereits erklärt, wofür jedes Muster steht.
Ich werde wichtige Punkte dekorieren .
Dekorateur:
zB (mit Verkettung):
java.io
Paketklassen, die sich aufInputStream
&OutputStream
interfaces beziehenProxy:
zB:
java.rmi
Paketklassen.Adapter:
zB
java.io.InputStreamReader
(InputStream
gibt a zurückReader
)Brücke:
zB Sammlungsklassen in
java.util
.List
implementiert vonArrayList
.Wichtige Hinweise:
Schauen Sie sich großartige SE-Fragen / Artikel zu Beispielen für verschiedene Designmuster an
Wann sollte das Dekorationsmuster verwendet werden?
Wann verwenden Sie das Brückenmuster? Wie unterscheidet es sich vom Adaptermuster?
Unterschiede zwischen Proxy- und Decorator-Muster
quelle
Sie sind ziemlich ähnlich und die Linien zwischen ihnen sind ziemlich grau. Ich schlage vor, Sie lesen die Einträge Proxy Pattern und Decorator Pattern im c2-Wiki.
Die Einträge und Diskussionen dort sind recht umfangreich und sie verlinken auch auf andere relevante Artikel. Das c2-Wiki eignet sich übrigens hervorragend, wenn man sich über die Nuancen zwischen verschiedenen Mustern wundert.
Um die c2-Einträge zusammenzufassen, würde ich sagen, dass ein Dekorateur das Verhalten hinzufügt / ändert, aber ein Proxy hat mehr mit der Zugriffskontrolle zu tun (verzögerte Instanziierung, Remotezugriff, Sicherheit usw.). Aber wie gesagt, die Linien zwischen ihnen sind grau, und ich sehe Verweise auf Proxys, die leicht als Dekorateure angesehen werden können und umgekehrt.
quelle
Alle vier Muster beinhalten das Umschließen des inneren Objekts / der inneren Klasse mit dem äußeren, so dass sie strukturell sehr ähnlich sind. Ich würde den Unterschied durch den Zweck skizzieren:
Und durch Schnittstellenvariationen zwischen inneren und äußeren Objekten:
quelle
Dies ist ein Zitat aus Head First Design Patterns
Definitionen gehören zum Buch. Beispiele gehören mir.
Dekorateur - Ändert die Benutzeroberfläche nicht, fügt aber Verantwortung hinzu. Angenommen, Sie haben eine Fahrzeugschnittstelle. Wenn Sie diese für verschiedene Fahrzeugmodelle (s, sv, sl) implementieren, müssen Sie möglicherweise mehr Verantwortung hinzufügen für einige Modelle . Wie hat Schiebedach, Airbag etc ..
Adapter - Konvertiert eine Schnittstelle in eine andere. Sie haben eine Autoschnittstelle und möchten, dass sie sich wie ein Jeep verhält. Also nimmst du das Auto, modifizierst es und verwandelst dich in einen Jeep. Da ist es kein richtiger Jeep. Aber wirkt wie ein Jeep.
Fassade - Vereinfacht die Benutzeroberfläche. Angenommen, Sie haben Auto-, Flugzeug- und Schiffsschnittstellen. Eigentlich brauchen Sie nur eine Klasse, die Leute von einem Ort zum anderen schickt. Sie möchten, dass die Fassade entscheidet, welches Fahrzeug verwendet wird. Dann sammeln Sie alle diese Schnittstellenreferenzen unter einem Dach und lassen es entscheiden / delegieren, um es einfach zu halten.
Head First: "Eine Fassade vereinfacht nicht nur eine Schnittstelle, sondern entkoppelt einen Client von einem Teilsystem von Komponenten. Fassaden und Adapter können mehrere Klassen umschließen, aber eine Fassade soll vereinfacht werden, während ein Adapter die Schnittstelle in etwas anderes konvertieren soll. ""
quelle
Ich benutze es ziemlich oft, wenn ich Webdienste konsumiere. Das Proxy-Muster sollte wahrscheinlich in etwas Pragmatischeres wie "Wrapper-Muster" umbenannt werden. Ich habe auch eine Bibliothek, die ein Proxy für MS Excel ist. Es macht es sehr einfach, Excel zu automatisieren, ohne sich um Hintergrunddetails wie das kümmern zu müssen Version ist installiert (falls vorhanden).
quelle
Bei der Detailimplementierung finde ich einen Unterschied zwischen Proxy und Decorator, Adapter, Fassade ... Bei der allgemeinen Implementierung dieser Muster gibt es ein Zielobjekt, das von einem umschließenden Objekt umschlossen wird. Der Client verwendet ein umschließendes Objekt anstelle eines Zielobjekts. Und das Zielobjekt spielt tatsächlich eine wichtige Rolle bei einigen Methoden zum Einschließen von Objekten.
Im Fall von Proxy kann das einschließende Objekt jedoch einige Methoden selbst abspielen. Es initialisiert nur das Zielobjekt, wenn der Client einige Methoden aufruft, an denen das Zielobjekt teilnehmen muss. Dies ist eine verzögerte Initialisierung. Bei anderen Mustern basiert das umschließende Objekt virtuell auf dem Zielobjekt. Das Zielobjekt wird also immer zusammen mit dem Einschließen des Objekts in Konstruktoren / Setter initialisiert.
Eine andere Sache ist, dass ein Proxy genau das tut, was ein Ziel tut, während andere Muster dem Ziel mehr Funktionalität hinzufügen.
quelle
Ich möchte der Antwort von Bill Karwing Beispiele hinzufügen (was übrigens großartig ist). Ich füge auch einige wichtige Unterschiede bei der Implementierung hinzu, die meiner Meinung nach fehlen
Zitierte Teile stammen aus der Antwort von [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)
ProxyClass und ObjectClass, die als Proxy fungieren, sollten dieselbe Schnittstelle implementieren, damit sie austauschbar sind
Beispiel - Proxy teures Objekt
DecoratorClass sollte (könnte) eine erweiterte Schnittstelle von ObjectClass implementieren. Die ObjectClass könnte also durch DecoratorClass ersetzt werden, aber nicht umgekehrt.
Beispiel - Hinzufügen von Zusatzfunktionen
Implementierungsunterschiede Proxy, Decorator, Adapter
Der Adapter bietet eine andere Schnittstelle zu seinem Thema. Proxy bietet die gleiche Schnittstelle. Decorator bietet eine erweiterte Oberfläche.
Die meisten Informationen in dieser Antwort stammen von https://sourcemaking.com/design_patterns , die ich als hervorragende Ressource für Entwurfsmuster empfehle .
quelle
Ich glaube, dass Code klare Ideen liefert (um auch andere Antworten zu ergänzen). Siehe unten (Konzentrieren Sie sich auf die Typen, die eine Klasse implementiert und umschließt).
quelle
Entwurfsmuster sind keine Mathematik, sondern eine Kombination aus Kunst und Softwareentwicklung. Es gibt nichts Vergleichbares für diese Anforderung, dass Sie Proxy, Bridge usw. verwenden müssen. Entwurfsmuster werden erstellt, um die Probleme zu lösen. Wenn Sie ein Designproblem antizipieren, verwenden Sie es. Basierend auf der Erfahrung werden Sie für ein bestimmtes Problem wissen, welches Muster verwendet werden soll. Wenn Sie sich mit soliden Entwurfsprinzipien auskennen, hätten Sie ein Entwurfsmuster implementiert, ohne zu wissen, dass es sich um ein Muster handelt. Ein häufiges Beispiel sind Statergie und Fabrikmuster
Konzentrieren Sie sich daher mehr auf solide Desighn-Prinzipien, Clean-Coding-Prinzipien und ttd
quelle