Je regardais le modèle de proxy, et pour moi, cela ressemble énormément aux modèles de décorateur, d'adaptateur et de pont. Suis-je en train de mal comprendre quelque chose? Quelle est la différence? Pourquoi devrais-je utiliser le modèle de proxy par rapport aux autres? Comment les avez-vous utilisés dans le passé dans des projets du monde réel?
design-patterns
decorator
bridge
proxy-pattern
Charles Graham
la source
la source
Réponses:
Le proxy, le décorateur, l'adaptateur et le pont sont tous des variantes de "l'habillage" d'une classe. Mais leurs utilisations sont différentes.
Le proxy peut être utilisé lorsque vous souhaitez instancier un objet paresseusement, masquer le fait que vous appelez un service distant ou contrôler l'accès à l'objet.
Le décorateur est également appelé «Smart Proxy». Ceci est utilisé lorsque vous souhaitez ajouter des fonctionnalités à un objet, mais pas en étendant le type de cet objet. Cela vous permet de le faire lors de l'exécution.
L'adaptateur est utilisé lorsque vous avez une interface abstraite et que vous souhaitez mapper cette interface à un autre objet qui a un rôle fonctionnel similaire, mais une interface différente.
Bridge est très similaire à Adapter, mais nous l'appelons Bridge lorsque vous définissez à la fois l'interface abstraite et l'implémentation sous-jacente. C'est-à-dire que vous ne vous adaptez pas à un code hérité ou tiers, vous êtes le concepteur de tout le code, mais vous devez pouvoir échanger différentes implémentations.
La façade est une interface de niveau supérieur (lire: plus simple) vers un sous-système d'une ou plusieurs classes. Supposons que vous ayez un concept complexe qui nécessite la représentation de plusieurs objets. Apporter des modifications à cet ensemble d'objets est source de confusion, car vous ne savez pas toujours quel objet possède la méthode que vous devez appeler. C'est le moment d'écrire une façade qui fournit des méthodes de haut niveau pour toutes les opérations complexes que vous pouvez effectuer pour la collection d'objets. Exemple: un modèle de domaine pour une section de l' école, avec des méthodes comme
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
et ainsi de suite.la source
Comme le dit la réponse de Bill, leurs cas d'utilisation sont différents .
Leurs structures aussi.
Le proxy et le décorateur ont tous deux la même interface que leurs types encapsulés, mais le proxy crée une instance sous le capot, tandis que le décorateur prend une instance dans le constructeur.
L'adaptateur et la façade ont tous deux une interface différente de ce qu'ils enveloppent. Mais l'adaptateur dérive d'une interface existante, tandis que la façade crée une nouvelle interface.
Le pont et l' adaptateur pointent tous deux vers un type existant. Mais le pont pointe vers un type abstrait et l'adaptateur peut pointer vers un type concret. Le pont vous permettra de coupler l'implémentation lors de l'exécution, contrairement à l'adaptateur.
la source
Mon point de vue sur le sujet.
Les quatre modèles ont beaucoup en commun, tous les quatre sont parfois appelés de manière informelle wrappers ou wrapper patterns. Tous utilisent la composition, enveloppant le sujet et déléguant l'exécution au sujet à un moment donné, mappent un appel de méthode à un autre. Ils épargnent au client la nécessité de devoir construire un objet différent et de copier toutes les données pertinentes. S'ils sont utilisés à bon escient, ils économisent de la mémoire et du processeur.
En favorisant le couplage lâche, ils rendent le code autrefois stable moins exposé aux changements inévitables et mieux lisible pour les autres développeurs.
Adaptateur
L'adaptateur adapte le sujet (adaptee) à une interface différente. De cette façon, nous pouvons ajouter un objet à placer dans une collection de types nominalement différents.
L'adaptateur expose uniquement les méthodes pertinentes au client, peut restreindre toutes les autres, révélant des intentions d'utilisation pour des contextes particuliers, comme l'adaptation d'une bibliothèque externe, la faisant apparaître moins générale et plus axée sur les besoins de notre application. Les adaptateurs améliorent la lisibilité et l'auto-description de notre code.
Les adaptateurs protègent une équipe du code volatil des autres équipes; un outil de sauvetage quand il s'agit d'équipes offshore ;-)
Moins mentionné, il vise à empêcher la classe de matière d'un excès d'annotations. Avec autant de frameworks basés sur des annotations, cela devient plus important que jamais.
L'adaptateur permet de contourner la limitation Java de l'héritage unique. Il peut combiner plusieurs adaptations sous une seule enveloppe donnant une impression d'héritage multiple.
En ce qui concerne le code, l'adaptateur est «mince». Il ne devrait pas ajouter beaucoup de code à la classe adaptee, en plus d'appeler simplement la méthode adaptee et des conversions de données occasionnelles nécessaires pour effectuer de tels appels.
Il n'y a pas beaucoup de bons exemples d'adaptateurs dans JDK ou dans les bibliothèques de base. Les développeurs d'applications créent des adaptateurs pour adapter les bibliothèques aux interfaces spécifiques à l'application.
Décorateur
Le décorateur non seulement délègue, mappe non seulement une méthode à une autre, il en fait plus, il modifie le comportement de certaines méthodes de sujet, il peut décider de ne pas appeler la méthode de sujet du tout, de déléguer à un autre objet, un objet d'aide.
Les décorateurs ajoutent généralement (de manière transparente) des fonctionnalités à l'objet encapsulé comme la journalisation, le chiffrement, le formatage ou la compression du sujet. Cette nouvelle fonctionnalité peut apporter beaucoup de nouveau code. Par conséquent, les décorateurs sont généralement beaucoup plus «gros» que les adaptateurs.
Le décorateur doit être une sous-classe de l'interface du sujet. Ils peuvent être utilisés de manière transparente au lieu de ses sujets. Voir BufferedOutputStream, il s'agit toujours de OutputStream et peut être utilisé comme tel. C'est une différence technique majeure par rapport aux adaptateurs.
Des exemples de manuels de toute la famille des décorateurs sont facilement disponibles dans JDK - Java IO. Toutes les classes comme BufferedOutputStream , FilterOutputStream et ObjectOutputStream sont des décorateurs de OutputStream . Ils peuvent être en couches d'oignon, où un décorateur est à nouveau décoré, ajoutant plus de fonctionnalités.
Procuration
Le proxy n'est pas un wrapper typique. L'objet encapsulé, le sujet proxy, peut ne pas encore exister au moment de la création du proxy. Le proxy le crée souvent en interne. Il peut s'agir d'un objet lourd créé à la demande, ou d'un objet distant dans une JVM ou un nœud de réseau différent et même un objet non Java, un composant en code natif. Il n'a pas besoin d'envelopper ou de déléguer à un autre objet.
Les exemples les plus typiques sont les proxys distants, les initialiseurs d'objets lourds et les proxys d'accès.
Proxy distant - le sujet se trouve sur un serveur distant, une JVM différente ou même un système non Java. Le proxy traduit les appels de méthode en appels RMI / REST / SOAP ou tout ce qui est nécessaire, protégeant le client de l'exposition à la technologie sous-jacente.
Lazy Load Proxy - initialise complètement l'objet uniquement lors de la première utilisation ou de la première utilisation intensive.
Proxy d'accès - contrôlez l'accès au sujet.
Façade
La façade est étroitement associée au principe de conception des moindres connaissances (loi de Déméter). La façade est très similaire à l'adaptateur. Ils enveloppent tous les deux, ils mappent tous les deux un objet à un autre, mais ils diffèrent dans l'intention. La façade aplatit la structure complexe d'un sujet, le graphique d'objet complexe, simplifiant l'accès à une structure complexe.
La façade enveloppe une structure complexe, lui fournissant une interface plate. Cela empêche l'objet client d'être exposé aux relations internes dans la structure du sujet, ce qui favorise le couplage lâche.
Pont
Variante plus complexe du modèle d'adaptateur où non seulement l'implémentation varie mais aussi l'abstraction. Il ajoute une indirection supplémentaire à la délégation. La délégation supplémentaire est le pont. Il dissocie l'adaptateur même de l'adaptation de l'interface. Il augmente la complexité plus que tout autre des autres modèles d'emballage, alors appliquez avec soin.
Différences de constructeurs
Les différences de modèle sont également évidentes lorsque l'on regarde leurs constructeurs.
Le proxy n'encapsule pas un objet existant. Il n'y a pas de sujet dans le constructeur.
Décorateur et adaptateur encapsule un objet déjà existant, et tel est généralement
fourni dans le constructeur.
Le constructeur de façade prend l'élément racine d'un graphique d'objet entier, sinon il ressemble à Adapter.
Exemple réel - Adaptateur de marshaling JAXB . Le but de cet adaptateur est de mapper une classe plate simple à une structure plus complexe requise en externe et d'éviter la classe de sujet "polluante" avec des annotations excessives.
la source
Il y a beaucoup de chevauchements dans de nombreux modèles du GoF. Ils sont tous construits sur le pouvoir du polymorphisme et parfois ne diffèrent vraiment que dans leur intention. (stratégie vs état)
Ma compréhension des modèles a été multipliée par 100 après avoir lu les modèles de conception Head First .
Je le recommande fortement!
la source
Toutes les bonnes réponses des experts ont déjà expliqué ce que représente chaque modèle.
Je décorerai les points clés.
Décorateur:
par exemple (avec chaînage):
java.io
classes de packages liées auxInputStream
&OutputStream
interfacesProcuration:
par exemple:
java.rmi
classes de packages.Adaptateur:
par exemple
java.io.InputStreamReader
(InputStream
renvoie aReader
)Pont:
par exemple des cours Collection en
java.util
.List
mis en œuvre parArrayList
.Notes clés:
Jetez un oeil à de grandes questions / articles SE concernant des exemples de différents modèles de conception
Quand utiliser le motif décorateur?
Quand utilisez-vous le Bridge Pattern? En quoi est-il différent du modèle d'adaptateur?
Différences entre le proxy et le modèle de décorateur
la source
Ils sont assez similaires et les lignes entre eux sont assez grises. Je vous suggère de lire les entrées Proxy Pattern et Decorator Pattern dans le wiki c2.
Les entrées et les discussions y sont assez nombreuses, et elles renvoient également à d'autres articles pertinents. Soit dit en passant, le wiki c2 est excellent lorsque l'on s'interroge sur les nuances entre les différents modèles.
Pour résumer les entrées c2, je dirais qu'un décorateur ajoute / modifie le comportement, mais un proxy a plus à voir avec le contrôle d'accès (instanciation paresseuse, accès à distance, sécurité, etc.). Mais comme je l'ai dit, les lignes entre eux sont grises et je vois des références à des mandataires qui pourraient facilement être considérés comme des décorateurs et vice versa.
la source
Tous les quatre modèles impliquent d'envelopper un objet / classe interne avec un objet externe, ils sont donc très similaires structurellement. Je soulignerais la différence par le but:
Et par variation d'interface entre les objets internes et externes:
la source
Ceci est une citation de Head First Design Patterns
Les définitions appartiennent au livre. Les exemples m'appartiennent.
Décorateur - Ne modifie pas l'interface, mais ajoute des responsabilités. Supposons que vous ayez une interface de voiture, lorsque vous l'implémentez pour différents modèles de voiture (s, sv, sl), vous devrez peut-être ajouter plus de responsabilité pour certains modèles. Comme le toit ouvrant, l'airbag, etc.
Adaptateur - Convertit une interface en une autre. Vous avez une interface de voiture et vous aimeriez qu'elle agisse comme une jeep. Vous prenez donc la voiture, la modifiez et vous vous transformez en jeep. Comme ce n'est pas une vraie jeep. Mais agit comme une jeep.
Façade - Rend une interface plus simple. Supposons que vous ayez des interfaces voiture, avion, navire. En fait, tout ce dont vous avez besoin est une classe qui envoie des gens d'un endroit à un autre. Vous voulez que la façade décide du véhicule à utiliser. Ensuite, vous rassemblez toutes ces références d'interface sous 1 parapluie et laissez-le décider / déléguer pour rester simple.
Head First: "Une façade simplifie non seulement une interface, elle dissocie un client d'un sous-système de composants. Les façades et les adaptateurs peuvent encapsuler plusieurs classes, mais l'intention d'une façade est de simplifier, tandis qu'un adaptateur consiste à convertir l'interface en quelque chose de différent. "
la source
Je l'utilise assez souvent lors de la consommation de services Web. Le modèle de proxy devrait probablement être renommé en quelque chose de plus pragmatique, comme «Wrapper Pattern". J'ai également une bibliothèque qui est un proxy pour MS Excel. Cela facilite l'automatisation d'Excel, sans avoir à se soucier des détails d'arrière-plan tels que la version est installée (le cas échéant).
la source
En parlant d'implémentation détaillée, je trouve une différence entre Proxy et Decorator, Adapter, Facade ... Dans l'implémentation courante de ces modèles, il y a un objet cible enveloppé par un objet englobant. Le client utilise un objet englobant au lieu de l'objet cible. Et l'objet cible joue en fait un rôle important à l'intérieur de certaines méthodes de confinement de l'objet.
Cependant, dans le cas du proxy, un objet englobant peut jouer certaines méthodes par lui-même, il initialise simplement l'objet cible lorsque le client appelle certaines méthodes dont il a besoin que l'objet cible participe. Il s'agit d'une initialisation paresseuse. Dans le cas d'autres modèles, entourer l'objet est virtuellement basé sur l'objet cible. Ainsi, l'objet cible est toujours initialisé avec l'objet englobant dans les constructeurs / setters.
Une autre chose, un proxy fait exactement ce que fait une cible tandis que d'autres modèles ajoutent plus de fonctionnalités à la cible.
la source
Je voudrais ajouter des exemples à la réponse de Bill Karwing (ce qui est très bien.) J'ajoute également quelques différences clés de mise en œuvre qui, selon moi, manquent
Les parties citées proviennent de la réponse de [ https://stackoverflow.com/a/350471/1984346] (Bill Karwing)
ProxyClass et ObjectClass qui sont mandatés, doivent implémenter la même interface, afin qu'ils soient interchangeables
Exemple - objet cher proxy
DecoratorClass devrait (pourrait) implémenter une interface étendue d'ObjectClass. Ainsi, l'ObjectClass pourrait être remplacé par DecoratorClass, mais pas l'inverse.
Exemple - ajout de fonctionnalités supplémentaires
Différences d'implantation Proxy, Decorator, Adapter
L'adaptateur fournit une interface différente à son sujet. Le proxy fournit la même interface. Decorator fournit une interface améliorée.
La plupart des informations dans cette réponse proviennent de https://sourcemaking.com/design_patterns , que je recommande comme une excellente ressource pour les modèles de conception.
la source
Je crois que le code donnera des idées claires (pour compléter les autres réponses également). Veuillez voir ci-dessous, (Concentrez-vous sur les types qu'une classe implémente et encapsule)
la source
Le modèle de conception n'est pas des mathématiques, c'est une combinaison d'art et de génie logiciel. Il n'y a rien de tel pour cette exigence que vous devez utiliser un proxy, un pont, etc. Des modèles de conception sont créés pour résoudre les problèmes. Si vous prévoyez un problème de conception, utilisez-le. Sur la base de l'expérience, vous découvrirez, pour un problème spécifique, quel modèle utiliser. Si vous êtes bon dans les principes de conception solides, vous auriez implémenté un modèle de conception sans savoir qu'il s'agit d'un modèle. Un exemple courant est les modèles de statergy et d'usine
Par conséquent, concentrez-vous davantage sur les principes de conception solides, les principes de codage propre et le ttd
la source