Question

Je regardais le modèle de proxy et, pour moi, il ressemble beaucoup aux modèles de décorateur, d’adaptateur et de pont. Est-ce que je comprends mal quelque chose? Quelle est la différence? Pourquoi utiliser le modèle de proxy par rapport aux autres? Comment les avez-vous utilisés dans le passé dans des projets concrets?

Était-ce utile?

La solution

Proxy, Decorator, Adapter et Bridge sont des variantes de & "wrapping &"; une classe. Mais leurs utilisations sont différentes.

  • Le proxy peut être utilisé lorsque vous souhaitez instancier paresseusement un objet, ou masquer le fait que vous appelez un service distant ou que vous contrôlez l'accès à l'objet.

  • Decorator est également appelé & "Serveur intelligent. &"; Ceci est utilisé lorsque vous souhaitez ajouter une fonctionnalité à un objet, mais pas en étendant le type de cet objet. Cela vous permet de le faire au moment de l'exécution.

  • Adaptateur est utilisé lorsque vous avez une interface abstraite et que vous souhaitez mapper cette interface sur un autre objet ayant 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. vous ne vous adaptez pas à un code hérité ou tiers, vous êtes le concepteur de tout le code, mais vous devez pouvoir échanger des implémentations différentes.

  • Facade est une interface de niveau supérieur (lecture: plus simple) menant à un sous-système d'une ou de 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 a la méthode à 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 sur la collection d'objets. Exemple: un modèle de domaine pour une section d'école, avec des méthodes telles que countStudents(), reportAttendance(), assignSubstituteTeacher() et ainsi de suite.

Autres conseils

Comme le dit la réponse de Bill, leurs cas d'utilisation sont différents .

Telles sont leurs structures.

  • Le proxy et Décorateur ont la même interface que leurs types enveloppé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 Façade possèdent tous deux une interface différente de celle utilisée. Mais l'adaptateur dérive d'une interface existante, alors que la façade crée une nouvelle interface.

  • Le pont et Adaptateur pointent tous deux sur un type existant. Mais le pont pointe vers un type abstrait et l'adaptateur peut pointer vers un type concret. Le pont vous permettra d'associer l'implémentation au moment de l'exécution, alors que l'adaptateur ne le fera généralement pas.

Mon point de vue sur le sujet.

Les quatre modèles ont beaucoup en commun. Ils sont parfois appelés de manière informelle des wrappers ou des modèles de wrapper. Tous utilisent la composition, encapsulant le sujet et déléguant l'exécution au sujet à un moment donné, mappent un appel de méthode à un autre. Ils évitent au client la nécessité de construire un objet différent et de copier toutes les données pertinentes. Utilisés judicieusement, ils économisent de la mémoire et du processeur.

En favorisant les couplages lâches, ils rendent le code une fois stable moins exposé aux changements inévitables et plus lisible par les autres développeurs.

Adaptateur

Adapter adapte le sujet (adapté) à une interface différente. De cette façon, nous pouvons ajouter un objet à une collection de types nominalement différents.

Adapter n'expose que les méthodes pertinentes au client, peut restreindre toutes les autres, révélant les intentions d'utilisation pour des contextes particuliers, comme l'adaptation d'une bibliothèque externe, le rendant moins général et plus ciblé sur les besoins de nos applications. Les adaptateurs augmentent la lisibilité et l'auto-description de notre code.

Les adaptateurs protègent une équipe du code instable des autres équipes; un outil de sauvetage dans les relations avec les équipes offshore;)

Le terme moins mentionné a pour but d’empêcher la classe de sujets de dépasser le nombre d’annotations. Avec autant de frameworks basés sur des annotations, cela devient une utilisation plus importante que jamais.

Adapter permet de contourner la limitation Java d’un héritage unique. Il peut combiner plusieurs composants sous une même enveloppe, donnant ainsi l’impression d’un héritage multiple.

En ce qui concerne le code, l’adaptateur est & # 8220; mince & # 8221 ;. Il ne faut pas ajouter beaucoup de code à la classe adaptee, à part simplement appeler la méthode adaptee et effectuer 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 à une application.

Décorateur

Le décorateur non seulement délègue, mappe 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 de méthode du sujet, de déléguer à un autre objet, un objet d'assistance.

Les décorateurs ajoutent généralement (de manière transparente) des fonctionnalités aux objets enveloppés, telles que la journalisation, le cryptage, le formatage ou la compression sur le sujet. Cette nouvelle fonctionnalité peut apporter beaucoup de nouveau code. Par conséquent, les décorateurs sont généralement beaucoup & # 8220; plus gros & # 8221; puis des adaptateurs.

Decorator 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 reste OutputStream et peut être utilisé en tant que tel. C’est une différence technique majeure par rapport aux adaptateurs.

Des exemples de manuels de la famille de décorateurs entiers se trouvent facilement dans JDK - Java IO. Toutes les classes comme BufferedOutputStream , FilterOutputStream et ObjectOutputStream sont les décorateurs de OutputStream . Ils peuvent être superposés, un décorateur étant à nouveau décoré, ce qui ajoute davantage de fonctionnalités.

Proxy

Le proxy n'est pas un wrapper typique. L'objet encapsulé, le sujet du proxy, peut ne pas 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 machine virtuelle Java ou un noeud de réseau différent, voire d'un objet non Java, d'un composant en code natif. Il n’est pas nécessaire qu’il soit encapsulé ou délégué à un autre objet.

La plupart des exemples typiques sont à distanceles mandataires, les initialiseurs d'objets lourds et les mandataires d'accès.

  • Proxy distant & # 8211; le sujet est sur un serveur distant, une machine virtuelle différente ou même non Système 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 aux technologie.

  • Proxy Lazy Load & # 8211; initialiser complètement l'objet que la première utilisation ou première utilisation intensive.

  • Proxy d'accès & # 8211; contrôler l'accès au sujet.

Façade

La façade est étroitement associée au principe de conception de la moindre connaissance (loi de Demeter). Facade est très similaire à Adapter. Ils enveloppent tous les deux, ils mappent un objet sur un autre, mais leur intention est différente. Façade aplatit la structure complexe d'un sujet, graphe d'objet complexe, simplifiant l'accès à une structure complexe.

Façade enveloppe une structure complexe en lui fournissant une interface plate. Cela empêche les objets clients d'être exposés à des relations internes dans la structure du sujet, favorisant ainsi un couplage lâche.

Pont

Variante plus complexe du modèle Adaptateur où non seulement la mise en œuvre 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'interface d'adaptation. Il augmente la complexité plus que tout autre motif d'emballage, appliquez-le donc avec soin.

Différences de constructeurs

Les différences de modèles sont également évidentes lorsque vous regardez leurs constructeurs.

  • Le proxy n'enveloppe pas un objet existant. Il n'y a pas de sujet dans le constructeur.

  • Decorator et Adaptateur encapsulent les objets existants, et il en est généralement ainsi

    fourni dans le constructeur.

  • Le constructeur
  • Facade prend l’élément racine d’un graphe d’objet entier, sinon il a l’air identique à l'adaptateur.

Exemple concret & # 8211; Adaptateur de coordination JAXB . Le but de cet adaptateur est de mapper une classe simple et plate sur une structure plus complexe requise en externe et pour empêcher & "Polluer &"; classe de sujet avec annotations excessives.

Beaucoup de modèles de GoF se chevauchent beaucoup. Ils sont tous construits sur la puissance du polymorphisme et parfois, leur intention ne diffère vraiment que de manière réelle. (stratégie contre état)

Ma compréhension des modèles a été multipliée par 100 après la lecture de Modèles de conception Head in .

Je le recommande vivement!

Toutes les bonnes réponses des experts ont déjà expliqué ce que chaque motif représente.

Je vais décorer les points clés.

Décorateur:

  1. Ajouter un comportement à l'objet au moment de l'exécution . L'héritage est la clé pour réaliser cette fonctionnalité, ce qui constitue à la fois un avantage et un inconvénient de ce modèle.
  2. Cela modifie le comportement de l'interface.

par exemple. (avec chaînage): java.io classes de paquetages liées à InputStream & amp; OutputStream interfaces

FileOutputStream fos1 = new FileOutputStream("data1.txt");  
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

Proxy:

  1. Utilisez-le pour l'initialisation lente, l'amélioration des performances en mettant en cache l'objet et en contrôlant l'accès au client / appelant . Il peut fournir un comportement alternatif ou appeler un objet réel. Au cours de ce processus, il peut créer un nouvel objet.
  2. Contrairement à Decorator , qui permet de chaîner des objets, le proxy ne permet pas de chaîner.

Par exemple: java.rmi les classes de package.

Adaptateur:

  1. Il permet à deux interfaces non liées de travailler ensemble à travers les différents objets , jouant éventuellement le même rôle.
  2. Il modifie l'interface d'origine .

par exemple. java.io.InputStreamReader (Reader retourne un java.util)

Pont:

  1. Il permet aux abstractions et aux implémentations de varier indépendamment .
  2. Il utilise la composition sur l'héritage .

par exemple. Classes de collecte dans List. ArrayList implémenté par <=>.

Remarques importantes:

  1. Adaptateur fournit une interface différente pour son sujet. Proxy fournit la même interface. Decorator fournit une interface améliorée.
  2. Adaptateur modifie l'interface d'un objet, Decorator accroît les responsabilités de l'objet.
  3. Decorator et Proxy ont des objectifs différents mais des structures similaires
  4. Adaptateur permet aux choses de fonctionner une fois conçues; Bridge les fait fonctionner avant d’être.
  5. Bridge est conçu à l’avance pour permettre à l’abstraction et à la mise en œuvre de varier indépendamment. L'adaptateur a été installé ultérieurement afin de permettre aux classes indépendantes de fonctionner ensemble
  6. Decorator est conçu pour vous permettre d'ajouter des responsabilités aux objets sans sous-classement.

Consultez d'excellentes questions / articles sur la SE concernant des exemples de différents modèles de conception

Quand utiliser le motif de décorateur?

Quand utilisez-vous le motif de pont? En quoi est-il différent du modèle d’adaptateur?

Différences entre les motifs de proxy et de décorateur

Ils sont assez similaires, et les lignes entre eux sont assez gris. Je vous suggère de lire le modèle de proxy et Modèle de décorateur entrées dans le wiki c2.

Les entrées et les discussions y sont assez volumineuses et renvoient également à d’autres articles pertinents. Soit dit en passant, le wiki c2 est excellent pour s’interroger sur les nuances entre 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 distant, 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.

Citation de Les premiers modèles de conception

Définitions appartient au livre. Les exemples m’appartiennent.

Décorateur : ne modifie pas l'interface, mais ajoute des responsabilités. Supposons que vous avez une interface de voiture, Lorsque vous implémentez cela pour différents modèles de voiture (s, sv, sl), vous devrez peut-être ajouter davantage de responsabilités pour certains modèles. Comme a toit ouvrant, airbag etc ..

Adaptateur : convertit une interface en une autre. Vous avez une interface de voiture et vous voudriez qu’elle se comporte comme une jeep. Donc, vous prenez la voiture, modifiez-la et transformez en une jeep. Comme ce n'est pas une vraie jeep. Mais se comporte comme une jeep.

Façade : simplifie l'interface. Supposons que vous ayez des interfaces voiture, avion, navire. En fait, tout ce dont vous avez besoin est une classe qui envoie les gens d'un endroit à un autre. Vous voulez que la façade décide quel véhicule utiliser. Ensuite, vous collectez toutes les références d'interface sous un même parapluie et laissez-le décider / déléguer pour que cela reste simple.

Head First: " Une façade simplifie non seulement une interface, mais dissocie également un client d'un sous-système des composants. Les façades et les adaptateurs peuvent envelopper plusieurs classes, mais une façade & # 8217; a pour but de simplifier, un adaptateur & # 8217; s consiste à convertir l'interface en quelque chose de différent. "

Tous les quatre modèles impliquent l’enveloppement d’un objet / classe interne avec un objet externe, ils sont donc très similaires structurellement. Je soulignerais la différence par le but:

  • Le proxy encapsule l'accès entre externe et interne.
  • Decorator modifie ou étend le comportement de interne à externe.
  • Adaptateur convertit l'interface de l'intérieur vers l'extérieur.
  • Bridge sépare une partie invariable du comportement (externe) de la partie variable ou dépendant de la plate-forme (interne).

Et par la variation d'interface entre les objets internes et externes:

  • dans les interfaces de proxy sont identiques.
  • dans Decorator , les interfaces sont identiques.
  • dans Les adaptateurs sont formellement différents, mais remplissent le même objectif.
  • dans Bridge , les interfaces sont différentes conceptuellement.

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, tel que 'Modèle de wrapper & ". J'ai aussi une bibliothèque qui est un proxy pour MS Excel. Il est très facile d'automatiser Excel, sans avoir à se soucier des détails de l'arrière-plan tels que la version installée (le cas échéant).

En parlant d’implémentation détaillée, je trouve une différence entre Proxy et Decorator, Adaptateur, Façade ... Dans l’implémentation commune de ces motifs, il y a un objet cible entouré par un objet englobant. Le client utilise un objet englobant au lieu d'un objet cible. Et l’objet cible joue en réalité un rôle important dans certaines méthodes d’objet englobant.

Cependant, dans le cas d'un proxy, l'objet englobant peut jouer certaines méthodes seul; il initialise simplement l'objet cible lorsque le client appelle certaines méthodes dont il a besoin. Cet initialisation est lente. Dans le cas d'autres modèles, l'objet englobant est virtuellement basé sur l'objet cible. Ainsi, l’objet cible est toujours initialisé avec l’objet englobant dans les constructeurs / setters.

Autre chose, un proxy fait exactement ce que fait une cible alors que d’autres modèles ajoutent plus de fonctionnalités à la cible.

Je voudrais ajouter des exemples à la réponse de Bill Karwing (ce qui est excellent en fait). J'ajoute également quelques différences clés de mise en œuvre qui me manquent

Les parties citées proviennent de la réponse de [ https://stackoverflow.com/a/350471/1984346] ( Bill Karwing)

  

Proxy, Decorator, Adapter et Bridge sont des variantes de & "wrapping &"; une classe.   Mais leurs utilisations sont différentes.

     
      
  • Un proxy peut être utilisé lorsque vous souhaitez instancier paresseusement un objet, ou   cachez le fait que vous appelez un service distant ou contrôlez l'accès   à l'objet.
  •   

ProxyClass et ObjectClass qui sont mandatés, doivent implémenter la même interface, donc interchangeables

Exemple - objet coûteux proxy

class ProxyHumanGenome implements GenomeInterface  {
    private $humanGenome = NULL; 

    // humanGenome class is not instantiated at construct time
    function __construct() {
    }

    function getGenomeCount() {
        if (NULL == $this->humanGenome) {
            $this->instantiateGenomeClass(); 
        }
        return $this->humanGenome->getGenomeCount();
    }
} 
class HumanGenome implement GenomeInterface { ... }
  
      
  • Decorator est également appelé & "Proxy intelligent. &"; Ceci est utilisé quand vous voulez   ajouter des fonctionnalités à un objet, mais pas en étendant celui de cet objet   type. Cela vous permet de le faire au moment de l'exécution.
  •   

DecoratorClass devrait (pourrait) implémenter l’interface étendue d’ObjectClass. Ainsi, ObjectClass pourrait être remplacé par DecoratorClass, mais pas l'inverse.

Exemple - ajout de fonctionnalités supplémentaires

class DecoratorHumanGenome implements CheckGenomeInterface  {

    // ... same code as previous example

    // added functionality
    public function isComplete() {
        $this->humanGenome->getCount >= 21000
    }
}

interface CheckGenomeInterface extends GenomeInterface {

    public function isComplete();

}

class HumanGenome implement GenomeInterface { ... }
  
      
  • Adaptateur est utilisé lorsque vous avez une interface abstraite et que vous souhaitez   mapper cette interface sur un autre objet ayant des fonctions similaires   rôle, mais une interface différente.
  •   

Différences d'implantation Proxy, Decorator, Adapter

Adapter fournit une interface différente pour son sujet. Le proxy fournit la même interface. Decorator fournit une interface améliorée.

  
      
  • Bridge est très similaire à Adapter, mais nous l'appelons Bridge lorsque vous   définir à la fois l'interface abstraite et l'implémentation sous-jacente.   C'est à dire. 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.

  •   
  • Facade est une interface de niveau supérieur (lecture: plus simple) menant à un sous-système de   une ou plusieurs classes. Supposons que vous ayez un concept complexe qui nécessite   plusieurs objets à représenter. Apporter des modifications à cet ensemble d'objets   est déroutant, parce que vous ne savez pas toujours quel objet a le   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   à la collection d'objets. Exemple: un modèle de domaine pour une école   section, avec des méthodes telles que countStudents(), reportAttendance(),   assignSubstituteTeacher() et ainsi de suite.

  •   

La plupart des informations dans cette réponse proviennent de https://sourcemaking.com/design_patterns , que je recommande comme excellente ressource pour les modèles de conception.

Je pense que le code donnera une idée claire (pour compléter les réponses des autres). Veuillez voir ci-dessous, (Concentrez-vous sur les types qu'une classe implémente et enveloppe)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            /* Proxy */

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("PROXY");
            Console.WriteLine(Environment.NewLine);

            //instead of creating here create using a factory method, the facory method will return the proxy
            IReal realProxy = new RealProxy();
            Console.WriteLine("calling do work with the proxy object ");
            realProxy.DoWork();

            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("ADAPTER");
            Console.WriteLine(Environment.NewLine);

            /*Adapter*/
            IInHand objectIHave = new InHand();
            Api myApi = new Api();
            //myApi.SomeApi(objectIHave); /*I cant do this, use a adapter then */
            IActual myAdaptedObject = new ActualAdapterForInHand(objectIHave);
            Console.WriteLine("calling api with  my adapted obj");
            myApi.SomeApi(myAdaptedObject);


            Console.WriteLine(Environment.NewLine);
            Console.WriteLine("DECORATOR");
            Console.WriteLine(Environment.NewLine);

            /*Decorator*/
            IReady maleReady = new Male();
            Console.WriteLine("now male is going to get ready himself");
            maleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReady = new Female();
            Console.WriteLine("now female is going to get ready her self");
            femaleReady.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady maleReadyByBeautician = new Beautician(maleReady);
            Console.WriteLine("now male is going to get ready by beautician");
            maleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            IReady femaleReadyByBeautician = new Beautician(femaleReady);
            Console.WriteLine("now female is going to get ready by beautician");
            femaleReadyByBeautician.GetReady();

            Console.WriteLine(Environment.NewLine);

            Console.ReadLine();


        }
    }

    /*Proxy*/

    public interface IReal
    {
        void DoWork();
    }

    public class Real : IReal
    {
        public void DoWork()
        {
            Console.WriteLine("real is doing work ");
        }
    }


    public class RealProxy : IReal
    {
        IReal real = new Real();

        public void DoWork()
        {
            real.DoWork();
        }
    }

    /*Adapter*/

    public interface IActual
    {
        void DoWork();
    }

    public class Api
    {
        public void SomeApi(IActual actual)
        {
            actual.DoWork();
        }
    }

    public interface IInHand
    {
        void DoWorkDifferently();
    }

    public class InHand : IInHand
    {
        public void DoWorkDifferently()
        {
            Console.WriteLine("doing work slightly different ");
        }
    }

    public class ActualAdapterForInHand : IActual
    {
        IInHand hand = null;

        public ActualAdapterForInHand()
        {
            hand = new InHand();
        }

        public ActualAdapterForInHand(IInHand hnd)
        {
            hand = hnd;
        }

        public void DoWork()
        {
            hand.DoWorkDifferently();
        }
    }

    /*Decorator*/

    public interface IReady
    {
        void GetReady();
    }

    public class Male : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
        }
    }

    public class Female : IReady
    {
        public void GetReady()
        {
            Console.WriteLine("Taking bath.. ");
            Console.WriteLine("Dress up....");
            Console.WriteLine("Make up....");
        }
    }

    //this is a decorator
    public class Beautician : IReady
    {
        IReady ready = null;

        public Beautician(IReady rdy)
        {
            ready = rdy;
        }

        public void GetReady()
        {
            ready.GetReady();
            Console.WriteLine("Style hair ");

            if (ready is Female)
            {
                for (int i = 1; i <= 10; i++)
                {
                    Console.WriteLine("doing ready process " + i);
                }

            }
        }
    }

}

Le modèle de conception n’est pas une mathématique, c’est une combinaison d’art et de génie logiciel. Il n'y a rien de tel que pour ce besoin, vous devez utiliser un proxy, un pont, etc. Des modèles de conception sont créés pour résoudre les problèmes. Si vous anticipez un problème de conception, utilisez-le. En fonction de votre expérience, vous découvrirez un problème spécifique et le modèle à utiliser. Si vous maîtrisez les principes de conception, vous auriez implémenté un modèle de conception sans savoir que c’est un modèle. Un exemple courant est celui de la statergy et des modèles d'usine

Par conséquent, concentrez-vous davantage sur des principes de référence solides, des principes de codage propres et des principes de base

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top