IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Tutoriel design pattern decorateur


Sujet :

C++

  1. #1
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut Tutoriel design pattern decorateur
    A la fin du tutoriel, il y a cette citation:

    En pratique, on chaîne souvent les constructions comme suit, bien que cela puisse réduire la lisibilité :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    BaseAliment *c= new  DecorateurGout( *(new Aliment(1.5,"Gauffre")),0.2,"Sucre") ;
    Mais je suis chagriné par le 2e new (new Aliment). Il a été alloué dynamiquement, mais ayant aucune référence sur le pointeur, comment peut-on le détruire?

  2. #2
    Membre du Club
    Profil pro
    Étudiant
    Inscrit en
    Août 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Août 2006
    Messages : 59
    Points : 59
    Points
    59
    Par défaut
    Pour le détruire, trois solutions:
    • Gérer la mémoire dans les Décorateurs.
    • Utiliser un smart pointer.
    • Utiliser un ramasseur de miette.


    En réalité, je pense (sans aucune certitude), que la mémoire doit être gérée dans les Décorateurs. En effet, une même variable pointe sur un nouvel objet à chaque ajout de décorateur. Le dernier objet créé (un décorateur en principe) se doit de détruire l'objet le précédent pour assurer une certaine transparence dans la gestion de la mémoire.

    En conclusion le constructeur de la classe Decorateur devrait se définir ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Decorateur::Decorateur(BaseAliment& base,double prix,const std::string& name):
    BaseAliment(prix,name),m_base(base)
    {
        delete base;
    }
    Mais ça reste risqué et celui qui utilise l'objet à plutôt intérêt à bien connaître son fonctionnement.
    De mon côté, ce qui me rend septique sont les performances de ce patron ?

    Edit: Mon exemple au dessus n'est pas valide, j'avais mal compris le fonctionnement et j'ai trop rapidement vus qu'il y avait utilisation d'un constructeur de copie au lieu d'une relation explicite par pointeur.

  3. #3
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    J'ai oublié le lien : http://come-david.developpez.com/tut...=Decorateur#LV

    En occurence, c'est aucun des 2 premières solutions.

    La 1e, gérer ça par la classe elle-même, je ne vois pas comment (comment savoir si l'objet fourni en paramètre a été construit statiquement ou dynamiquement?). Puis dans l'exemple, il y a aucun delete d'ailleurs.

    La 2e solution non plus, vu qu'il s'agit d'un pointeur classique.

    Je ne connais pas le ramasse-miette, mais je ne pense pas non plus en occurence ...

  4. #4
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Je confirme, le code d'exemple fuit sa mémoire comme ça ne devrait pas être permis (j'ai envie de dire que c'est une adaptation trop rapide d'un code java ou c#).

    Après, je ne connais pas ce pattern, donc je ne sais pas qui est censé géré la durée de vie des objets.

  5. #5
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    L'objectif de ce tutoriel était clairement de faire découvrir les DPs avec application en C++, l'accent a donc plus été mis sur l'aspect conception que sur la justesse du code C++.

    Toutefois, l'auteur prendra vos remarques en compte afin de faire une mise à jour, sans problème.

    En n'oubliant pas que les DPs, particulièrement en C++ grâce à la généricité, doivent être réutilisables, que proposeriez-vous pour régler le soucis ?

  6. #6
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    À mon avis, il faut gérer la durée de vie des objets dans le décorateur (et donc, stocker un pointeur plutôt qu'une reférence, et deleter m_base dans le destructeur de Decorateur). Je ne vois pas trop comment on peut s'en sortir autrement sinon.

    Ensuite, soit :
    - spécifier que l'objet BaseAliment doit avoir été alloué avec ::new
    - fournir une méthode statique Create(...) dans chacune des classes, et des constructeurs protégés (mieux)

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Si je comprend bien le pattern, il s'agit d'une composition. Donc, Decorateur devrait avoir un pointeur intelligent sur m_base; non?

  8. #8
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    A la base c'était juste une remarque, pour être sûr qu'il n'y a pas de destruction implicite si on fait appel au new dans un paramètre de fonction (on ne sait jamais, ça aurait pu être un détail que je connaissais pas, mais j'étais très sceptique).

    Juste pour dire qu'au lieu de faire un new dans le constructeur, faut d'abord déclarer une variable, puis la passer la référence. Cela évite ainsi toute fuite de mémoire.

    A ma connaissance, on ne peut pas faire un new sans garder une trace du pointeur afin qu'on puisse l'effacer par la suite.

    Ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    BaseAliment *c= new  DecorateurGout( *(new Aliment(1.5,"Gauffre")),0.2,"Sucre") ;
    devient

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Aliment a(1.5,"Gauffre");
    BaseAliment *c= new  DecorateurGout(&a,0.2,"Sucre") ;

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par Trunks Voir le message
    A ma connaissance, on ne peut pas faire un new sans garder une trace du pointeur afin qu'on puisse l'effacer par la suite.
    Avec une programmation rapide (pour ne pas dire plus), on pourrait faire quelque chose comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Decorateur::~Decorateur()
    {
    delete &m_base;
    }
    Avec 95% de chances d'avoir des plantages

    En fait, soit tu considères qu'il s'agit d'une composition, alors le décorateur doit avoir la responsabilité de créer et détruire l'élément.
    Soit il s'agit d'une simple association, et là, 2 solutions: ne pas utiliser d'allocation dynamique ou utiliser un shared_ptr.

  10. #10
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Aliment a(1.5,"Gauffre");
    BaseAliment *c= new  DecorateurGout(&a,0.2,"Sucre") ;
    très dangereux, car imagine le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    BaseAliment* f()
    {
       Aliment a(1.5,"Gauffre");
       BaseAliment *c= new  DecorateurGout(&a,0.2,"Sucre") ;
       return c;
    }
    Donc, soit comme l'a dit 3DArchi, un pointeur intelligent, soit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    BaseAliment* f()
    {
       BaseAliment *c=  DecorateurGout::Create(Aliment::Create(1.5,"Gauffre"),0.2,"Sucre") ;
       return c;
    }

  11. #11
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Aliment a(1.5,"Gauffre");
    BaseAliment *c= new  DecorateurGout(&a,0.2,"Sucre") ;
    très dangereux, car imagine le code suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    BaseAliment* f()
    {
       Aliment a(1.5,"Gauffre");
       BaseAliment *c= new  DecorateurGout(&a,0.2,"Sucre") ;
       return c;
    }
    Soit, ça dépend de la portée

    Citation Envoyé par white_tentacle Voir le message
    Donc, soit comme l'a dit 3DArchi, un pointeur intelligent, soit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    BaseAliment* f()
    {
       BaseAliment *c=  DecorateurGout::Create(Aliment::Create(1.5,"Gauffre"),0.2,"Sucre") ;
       return c;
    }
    Le pointeur intelligent, oui c'est une bonne solution en occurence.

    Tu peux m'en dire un peu plus pour DecorateurGout::Create et Aliment::Create?
    D'après la déclaration, il s'agit de fonctions statiques. Serait-ce une forme du design pattern Prototype. Pour Aliment::Create, comment est gérée la durée de vie?

  12. #12
    Membre chevronné
    Homme Profil pro
    edi
    Inscrit en
    Juin 2007
    Messages
    895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : edi

    Informations forums :
    Inscription : Juin 2007
    Messages : 895
    Points : 1 911
    Points
    1 911
    Par défaut
    Citation Envoyé par Trunks Voir le message
    Tu peux m'en dire un peu plus pour DecorateurGout::Create et Aliment::Create?
    D'après la déclaration, il s'agit de fonctions statiques. Serait-ce une forme du design pattern Prototype. Pour Aliment::Create, comment est gérée la durée de vie?
    Je crois que ce serait plutôt une factory (fonction ou classe qui a la charge de créer des objets).


    delete dans le décorateur ou pas, je crois que ça dépend aussi de la conception. Si la durée de vie du décorateur et du décoré sont liées, on peut mettre la destruction dedans ; je suppose que ça peut être le cas si l'on veut utiliser en les modifiant des objets venu d'une autre bibliothèque. Mais si le décorateur a une existance plus courte que le décoré, qu'il sert par exemple à adapter ou à modifier temporairement le comportement d'objet (par exemple si ont veut temporairement rediriger ou copier vers un fichier les messages d'un gestionnaire d'erreur), alors ça ne parait pas approprié. On pourrait aussi imaginer le cas où les objets de base (voire les décorateurs eux-même) sont créés par un manager qui prend en charge leur durée de vie.

    Un pointeur intelligent parait une option intéressante dans ces situations.

  13. #13
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Tu peux m'en dire un peu plus pour DecorateurGout::Create et Aliment::Create?
    D'après la déclaration, il s'agit de fonctions statiques. Serait-ce une forme du design pattern Prototype. Pour Aliment::Create, comment est gérée la durée de vie?
    Ça s'apparenterait plus à un pattern Factory.

    En fait, l'idée est de maîtriser la manière dont est allouée ton objet. Donc, tu mets un constructeur protégé, et une fonction statique de création (qui en l'occurrence, se conterait de faire un return new Aliment(...) ).

    Ensuite, il faut normalement aussi fournir une fonction de désallocation (pex Aliment:: Delete(Aliment*) ), qui libère les ressources.

    C'est identique à utiliser new et delete, mais l'avantage est que tu ne peux pas faire autrement que de les utiliser (contrairement à new/delete, et le problème du passage de référence à un objet alloué sur la pile).

  14. #14
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Aurais-tu un lien vers cette implémentation de la factory? Car l'imprémentation proposée ici est différente.

    Dans ton exemple, je ne vois toujours pas comment on peut libérer la mémoire pour aliment sans référence sur cette dernière (à moins qu'elle soit d'une manière ou d'une autre gérée par la factory).

    J'aimerais bien voir son implémentation dans ce cas

    Merci

  15. #15
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Loki::Factory ?

  16. #16
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Faudrait que je m'achète "Modern C++ Design"

    Bon, je vais mettre ce topic comme résolu. Vous être d'accord qu'il y a un problème de fuite mémoire dans l'exemple du tutoriel

  17. #17
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Ce n'est pas une vraie factory à proprement parler. On pourrait, mais la factory a forcément connaissance de tous les types qu'elle crée, ça va à l'inverse du décorateur .

    Dans ton exemple, je ne vois toujours pas comment on peut libérer la mémoire pour aliment sans référence sur cette dernière (à moins qu'elle soit d'une manière ou d'une autre gérée par la factory).
    C'est le décorateur qui libère la mémoire. Quand tu détruis le décorateur, il détruit l'objet qu'il décorait. Ce qui permet que tu ne doives te préoccupper que de libérer le décorateur (logique, puisque c'est cet objet là que tu utilises).

    Si le décorateur est temporaire, on peut imaginer une méthode detach pour enlever la décoration à un objet.

  18. #18
    Membre averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Merci pour ces réflexions, c'est toujours enrichissant

  19. #19
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par Trunks Voir le message
    Faudrait que je m'achète "Modern C++ Design"
    Je ne le recommanderai jamais assez, à qui que ce soit

    Citation Envoyé par white_tentacle Voir le message
    Ce n'est pas une vraie factory à proprement parler. On pourrait, mais la factory a forcément connaissance de tous les types qu'elle crée, ça va à l'inverse du décorateur .
    Oui et non. Après tu as l'abstract factory, voir des choses encore plus poussées qui combineraient programmation générative et des outils tels que boost::in_place_factory

    Citation Envoyé par white_tentacle Voir le message
    C'est le décorateur qui libère la mémoire. Quand tu détruis le décorateur, il détruit l'objet qu'il décorait. Ce qui permet que tu ne doives te préoccupper que de libérer le décorateur (logique, puisque c'est cet objet là que tu utilises).

    Si le décorateur est temporaire, on peut imaginer une méthode detach pour enlever la décoration à un objet.
    Ce système est assez similaire au système parent-enfant de Qt, où un parent doit libérer la mémoire de ses enfants.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. tutoriel design pattern (UML)
    Par Firas_tn dans le forum Design Patterns
    Réponses: 1
    Dernier message: 02/10/2007, 23h22
  2. Design Pattern : Tutoriels à télécharger
    Par Matthieu Brucher dans le forum Design Patterns
    Réponses: 0
    Dernier message: 06/07/2007, 12h43
  3. [Décorateur] [Java] Design Pattern Decorateur
    Par dralou dans le forum Design Patterns
    Réponses: 4
    Dernier message: 11/11/2006, 12h35
  4. Réponses: 8
    Dernier message: 30/09/2006, 06h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo