Différences entre le modèle de proxy et de décorateur

136

Pouvez-vous expliquer quelle est la différence entre Proxy et Decorator ?

La principale différence que je vois est que lorsque nous supposons que Proxy utilise la composition et que Decorator utilise l' agrégation, il semble être clair qu'en utilisant plusieurs (un ou plusieurs) décorateurs, vous pouvez modifier / ajouter des fonctionnalités à une instance préexistante (décorer), alors que Le proxy a sa propre instance interne de la classe mandatée et lui délègue l'ajout de fonctionnalités supplémentaires (comportement du proxy).

La question est - Est-ce que le proxy créé avec l'agrégation est toujours un proxy ou plutôt un décorateur ? Est-il autorisé (par définition dans les modèles GoF) à créer un proxy avec agrégation?

Łukasz Rzeszotarski
la source
2
Quelques liens: Proxy and Decorator
Sotirios Delimanolis
5
D'où vous est venue l'idée que Proxy utilise la composition et que Decorator utilise l'agrégation?
CPerkins
1
@CPerkins voir mon commentaire pour la réponse de Rahul Tripathi.
Łukasz Rzeszotarski
1
Et aussi décorateur ( patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - évidemment agrégation, proxy ( patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - évidemment la composition.
hyankov

Réponses:

17

Voici la citation directe du GoF (page 216).

Bien que les décorateurs puissent avoir des implémentations similaires en tant que mandataires, les décorateurs ont un objectif différent. Un décorateur ajoute une ou plusieurs responsabilités à un objet, tandis qu'un proxy contrôle l'accès à un objet.

Les procurations varient dans la mesure où elles sont mises en œuvre comme un décorateur. Un proxy de protection peut être implémenté exactement comme un décorateur. D'un autre côté, un proxy distant ne contiendra pas de référence directe à son sujet réel mais seulement une référence indirecte, telle que «ID d'hôte et adresse locale sur l'hôte». Un proxy virtuel démarrera avec une référence indirecte telle qu'un nom de fichier, mais finira par obtenir et utiliser une référence directe.

Les réponses courantes indiquent qu'un proxy connaît le type concret de son délégué. De cette citation, nous pouvons voir que ce n'est pas toujours vrai.

La différence entre Proxy et Decorator selon le GoF est que Proxy restreint le client. Le décorateur ne le fait pas. Le proxy peut restreindre ce qu'un client fait en contrôlant l'accès aux fonctionnalités; ou il peut restreindre ce qu'un client sait en effectuant des actions qui sont invisibles et inconnues du client. Le décorateur fait le contraire: il met en valeur ce que fait son délégué d'une manière visible pour les clients.

On pourrait dire que Proxy est une boîte noire tandis que Decorator est une boîte blanche.

La relation de composition entre le wrapper et le délégué est la mauvaise relation sur laquelle se concentrer lorsque vous comparez Proxy avec Decorator, car la composition est la caractéristique que ces deux modèles ont en commun. La relation entre le wrapper et le client est ce qui différencie ces deux modèles.

  • Le décorateur informe et responsabilise son client.
  • Proxy restreint et désautorise son client.
jaco0646
la source
114

La vraie différence n'est pas la propriété (composition contre agrégation), mais plutôt les informations de type.

Un décorateur est toujours son délégataire. Un mandataire pourrait le créer lui-même, ou il pourrait faire injecter.

Mais un proxy toujours connaît le type (plus) spécifique du délégataire. En d'autres termes, le proxy et son délégataire auront le même type de base, mais le proxy pointe vers un type dérivé. Un décorateur pointe vers son propre type de base. Ainsi, la différence réside dans les informations de compilation sur le type du délégataire.

Dans un langage dynamique, si le délégataire est injecté et a la même interface, alors il n'y a pas de différence.

La réponse à ta question est oui".

cdunn2001
la source
2
"Mais un mandataire connaît toujours le type (le plus) spécifique du délégataire." Je ne pense pas que ce soit vrai. Imaginez un proxy distant. Le mécanisme de proxy n'a pas besoin de connaître les spécificités de l'objet distant. Le système distant enregistre l'objet avec l'interface spécifiée. Et le proxy local expose la même interface.
Alexey
3
J'ai suivi un cours sur ce sujet chez Amazon avec un conférencier invité qui connaissait son métier. Il existe une différence entre l'utilisation d'un exécutable «proxy» (par exemple avec un service Web) et le Proxy Design Pattern. Les UML du modèle Proxy et du modèle Decorator peuvent être différents. Mais rien n'empêche un proxy d'avoir la même API que son délégataire. Decorator est un sous-ensemble strict de Proxy, mais un Decorator peut toujours être appelé Proxy selon que l'API sous-jacente est garantie d'être la même.
cdunn2001
85

Decorator Pattern se concentre sur l'ajout dynamique de fonctions à un objet, tandis que Proxy Pattern se concentre sur le contrôle de l'accès à un objet.

ÉDITER:-

La relation entre un proxy et le sujet réel est généralement définie au moment de la compilation, Proxy l' instancie d'une manière ou d'une autre, tandis que Decorator est assigné au sujet au moment de l'exécution, ne connaissant que l'interface du sujet.

Rahul Tripathi
la source
5
Un proxy peut cependant être utilisé pour ajouter des fonctionnalités. Pensez aux proxys AOP.
Sotirios Delimanolis
5
Tout à fait d'accord Monsieur. Je convertirais cela en d'autres termes, ce que je voulais dire était avec Proxy Pattern, la classe proxy peut cacher les informations détaillées d'un objet à son client. Par conséquent, lorsque vous utilisez Proxy Pattern, nous créons généralement une instance d'abject dans la classe proxy. Et lors de l'utilisation de Decorator Pattern, nous transmettons généralement l'objet d'origine en tant que paramètre au constructeur du décorateur.
Rahul Tripathi
Dans ce cas, lorsque l'instance est `` cachée '' dans le proxy, la différence est claire pour moi (comme je l'ai écrit), mais je pense que souvent les gens appellent comme des classes proxy qui prennent l'objet proxy qui a été passé comme paramètre du constructeur. Dans ce cas, la différence entre l'ajout de nouvelles fonctionnalités ou le contrôle est (très) mince pour moi.
Łukasz Rzeszotarski
5
La relation entre un proxy et le sujet réel est généralement définie au moment de la compilation, le proxy l'instancie d'une certaine manière, tandis que le décorateur ou l'adaptateur sont affectés au sujet au moment de l'exécution, ne connaissant que l'interface du sujet. J'espère que cela a du sens !!! :)
Rahul Tripathi
1
C'est vrai, vous pourriez ajouter cette ligne à votre réponse.
Łukasz Rzeszotarski
49

Le décorateur obtient la référence pour l'objet décoré (généralement via le constructeur) tandis que le proxy est responsable de le faire lui-même.

Le proxy peut ne pas instancier du tout l'objet d'encapsulation (comme cela, les ORM pour empêcher l'accès inutile à la base de données si les champs d'objet / obturateurs ne sont pas utilisés) tandis que Decorator conserve toujours le lien vers l'instance encapsulée réelle.

Proxy généralement utilisé par les frameworks pour ajouter la sécurité ou la mise en cache / lazing et construit par framework (pas par le développeur régulier lui-même).

Decorator généralement utilisé pour ajouter un nouveau comportement à des classes anciennes ou héritées par le développeur lui-même en fonction de l'interface plutôt que de la classe réelle (il fonctionne donc sur un large éventail d'instances d'interface, Proxy est autour de la classe concrète).

gavenkoa
la source
22

Principales différences:

  1. Proxy fournit la même interface. Decorator fournit une interface améliorée.
  2. Le décorateur et le mandataire ont des objectifs différents mais des structures similaires. Les deux décrivent comment fournir un niveau d'indirection vers un autre objet, et les implémentations conservent une référence à l'objet auquel elles transmettent les requêtes.
  3. Decorator peut être considéré comme un composite dégénéré avec un seul composant. Cependant, un décorateur ajoute des responsabilités supplémentaires - il n'est pas destiné à l'agrégation d'objets.
  4. Le décorateur prend en charge la composition récursive
  5. La classe Decorator déclare une relation de composition à l'interface LCD (plus petit dénominateur de classe) et ce membre de données est initialisé dans son constructeur.
  6. Utilisez Proxy pour l'initialisation paresseuse, l'amélioration des performances en mettant en cache l'objet et en contrôlant l'accès au client / appelant

L' article de sourcemaking cite les similitudes et les différences de manière excellente.

Questions / liens SE connexes:

Quand utiliser le motif décorateur?

Quelle est la différence exacte entre les modèles d'adaptateur et de proxy?

Ravindra babu
la source
3

Le mandataire et le décorateur diffèrent quant à leur objectif et à leur concentration sur la mise en œuvre interne. Le proxy permet d'utiliser un objet distant, inter-processus ou inter-réseau comme s'il s'agissait d'un objet local. Decorator sert à ajouter un nouveau comportement à l'interface d'origine.

Bien que les deux modèles aient une structure similaire, l'essentiel de la complexité de Proxy réside dans la garantie de communications appropriées avec l'objet source. Decorator, quant à lui, se concentre sur la mise en œuvre du comportement ajouté.

James Lin
la source
Que dites-vous qui est différent des 4 autres réponses déjà ici?
Stephen Rauch
Je ne sais pas si tout est là. J'ai juste ressenti le besoin d'intervenir après avoir lu les réponses précédentes.
James Lin
1

Il a fallu un certain temps pour comprendre cette réponse et ce qu'elle signifie vraiment. Quelques exemples devraient le rendre plus clair.

Proxy première:

public interface Authorization {
    String getToken();
} 

Et :

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

Et il y a un appelant de ceci Authorization, un assez stupide:

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

Rien d'inhabituel jusqu'à présent, non? Obtenez un jeton d'un certain service, utilisez ce jeton. Maintenant vient une autre exigence à l'image, ajouter la journalisation: ce qui signifie enregistrer le jeton à chaque fois. C'est simple pour ce cas, il suffit de créer un 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;
    }
}

Comment utiliserions-nous cela?

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

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

Notez que LoggingDBAuthorization contient une instance de DBAuthorization. Les deux LoggingDBAuthorizationet DBAuthorization mettre en œuvre Authorization .

  • Un proxy contiendra une implémentation concrète ( DBAuthorization) de l'interface de base ( Authorization). En d'autres termes, un proxy sait exactement ce qui est mandaté.

Decorator:

Cela commence à peu près de la même manière que Proxy, avec une interface:

public interface JobSeeker {
    int interviewScore();
}

et une mise en œuvre de celui-ci:

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

Et maintenant, nous voulons ajouter un candidat plus expérimenté, qui ajoute son score d'entrevue plus celui d'un autre JobSeeker:

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

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

Remarquez comment j'ai dit cela plus celui d'un autre chercheur d'emploi , non Newbie . A Decoratorne sait pas exactement ce qu'il décore, il ne connaît que le contrat de cette instance décorée (il connaît JobSeeker). Notez ici que cela ne ressemble pas à un Proxy; qui, en revanche, sait exactement ce qu'il décore.

Vous pourriez vous demander s'il y a réellement une différence entre les deux modèles de conception dans ce cas? Et si nous essayions d'écrire le en Decoratortant que Proxy?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

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

C'est certainement une option et met en évidence la proximité de ces modèles; ils sont toujours destinés à différents scénarios comme expliqué dans les autres réponses.

Eugène
la source
1

Proxy fournit la même interface à l'objet encapsulé , Decorator lui fournit une interface améliorée et Proxy gère généralement seul le cycle de vie de son objet de service, tandis que la composition de Decorators est toujours contrôlée par le client.

Ali Bayat
la source