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

Langage C++ Discussion :

Pattern Composite et templates


Sujet :

Langage C++

  1. #1
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut Pattern Composite et templates
    Je me suis replongé dans l'article de David Come sur les design patterns en C++, pour voir ce que je peux en tirer avec le C++11.

    L'auteur nous décrit plusieurs patterns, dont le Composite.
    De celui-ci en particulier, il dit qu'il ne se prête pas à la réalisation template.

    Hors, j'ai ce code dans mon projet actuel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include <vector>
    #include <functional>
    #include <initializer_list>
     
    template <class A>
    class Composite: public A {
    	public:
    		explicit Composite(){}
    		explicit Composite(std::initializer_list<A*> elements):elements(elements){}
     
    		~Composite() {for(A* a: elements) delete a;}
     
    		Composite& add(A* a) { elements.push_back(a); return *this; }
     
    	private:
            	std::vector<A*> elements;
    	protected:
    		void iterate(std::function<void(const A*)> const& f) const {
    			for(const A* a : elements) f(a);
    		}
    		void iterate(std::function<void(A*)> const& f){
    			for(A* a : elements) f(a);
    		}
    };
    Ce qui permet d'avoir, par exemple, ce genre d'usage:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    stuct Base{
    		virtual std::string content() const = 0;
    };
     
    class Leaf : public Base{
    	private:
    		std::string name;
    	public:
    		explicit Leaf(const std::string& name):name(name){}
    		std::string content() const {return name;}
    };
     
    class Node : public Composite<Base>{
    	public:
    		Node(std::initializer_list<Base*> elements):Composite<Base>(elements){}
     
    		std::string content() const {
    			std::ostringstream oss;
    			oss<<"[ ";
    			iterate( [&oss](const Base* b){oss<<(b->content())<<' ';} );
    			oss<<']';
    			return oss.str();
    		}
    };
    Qu'en pensez-vous? Est-ce vraiment utile?

  2. #2
    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
    Par défaut
    Salut,
    Citation Envoyé par leternel Voir le message
    Qu'en pensez-vous?
    Que la classe Composite ressemble plus à un conteneur. Une surcouche à std::vector en quelque sorte.

    Citation Envoyé par leternel Voir le message
    Est-ce vraiment utile?
    Quelle est la responsabilité de composite qui la distingue d'un conteneur ? Ou en d'autre termes, j'ai le sentiment qu'une surcouche a été rajoutée mais avec une faible valeur ajoutée.

  3. #3
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Le pattern composite est essentiellement de grouper plusieurs elements, et de se comporter comme l'un d'eux.

    en gros
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Composite<Bidule>: public Bidule{
        container<Bidule> contenu;
     
        //pour toute fonction f de bidule, 
        f = for (auto c : contenu) c.f
    };
    Dans les interfaces graphiques, par exemple, un panneau contenant des boutons est un ComposantGraphique, comme chacun des boutons.

    Dessiner le panneau appelle (entre autre) le dessin de chaque bouton.

    Il s'agit de mapper chaque fonction de l'interface sur l'ensemble des contenus.

    La classe que j'ai trouvé me semble n'être qu'un utilitaire, qui aurai d'ailleurs du être templaté aussi sur le type de conteneur.

  4. #4
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    @3DArchi: Ça ajoute une notion d'arborescence: Le composite peut contenir des (pointeurs vers) des objets de différents types d'une hiérarchie, y compris son propre type.

    C'est très utilisé en Interface Utilisateur Graphique (javax.swing.JComponent, System.Windows.Forms.Control, etc.)

    Par contre, ça nécessite du downcasting dès que tu veux accéder à des propriétés particulières d'un objet d'une classe dérivée. Je dirais que cette approche fais très "Java", bien qu'elle n'y soit pas limitée.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre très actif
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Par défaut
    J'avais cru comprendre que ce fil s'interrogeait sur l'incidence éventuelle de la nouvelle norme C+11 sur les design patterns en général, mais j'ai dû mal saisir le sens du titre du fil...
    Il s'agit apparemment d'une question sur un certain design pattern, et indépendamment de la nouvelle norme, non ?

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    initialement, je projetais de mettre à jour ma manière de réaliser les différents patterns en profitant des fonctionnalités du C++11.
    Je suis retourné sur les articles de développez.com abordant le sujet, et je soulevai le problème présent.

    De toutes façons, les patterns sont des concepts, indépendants de la norme et même du langage.

    Cela dit, je vais renommer le sujet, le titre "Composite et template" étant plus adapté.

  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
    Par défaut
    Fichtre. Je devrais savoir quand même que l'implicite est toujours de confusion.
    Même si le Gof n'est sorti qu'après la fin de mes études, c'est un classique que je connais. Ma remarque était sur la classe proposée en début de post. Je ne vois pas l'intérêt de la classe Composite donnée en exemple. Cette classe proposée en début de discussion me semble une sucrouche au conteneur avec peu de valeur ajoutée. D'où ma question, à quoi sert-elle ?

    De fait, j'ai l'impression que la remarque de David reste d'actualité : c'est un pattern qu'on peut construire à partir de générateur de code mais difficilement mettre en œuvre de façon générique.

  8. #8
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Finalement, vos avis confortent le mien.
    Cette classe Composite est éventuellement un simplificateur pour l'écriture du code, mais rien de vraiment utile.

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    AMA, la mise en place d'un patron "composite" sous la forme de template est très loin de n'être qu'une "figure de style" destinée à "simplifier l'écriture de code"...

    En effet, de manière générale, le pattern "Composite" est très utile dés qu'il faut pouvoir gérer des objets sous une forme arborescente (une racine / un tronc, des noeuds et des feuilles).

    Il arrive régulièrement que tu te retrouves, dans un projet d'envergure, face à la nécessité de disposer d'un nombre plus ou moins important de classe nécessitant ce patron.

    Le problème, si tu n'utilises pas la version template de ce patron de conception, c'est que tu vas finir par te retrouver avec une "multitude" de classe dérivant d'une seule et même classe de base alors que des pans entiers de cette arborescences devraient être clairement séparés des autres, en violation flagrante avec LSP.

    Je m'explique...:

    Imaginons que tu crées une bibliothèque d'interface graphique.

    Tous les widgets que tu vas créer sont susceptibles d'être contenus dans un widget "parent" et de contenir (ou non) des wigets "enfants".

    Bien sur, il n'est pas exclu que certains widgets ne puissent, décidément, pas contenir d'enfants et qu'ils soient donc les "feuilles" de ton arborescence.

    Tu pourrais donc imaginer de manière très logique d'utiliser le patron de conception "composite" avec un diagramme de classes qui pourrait ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          /Leaf----Button 
         /     \- Label
        /
    Base --- Node --- MenuItem
                   \- Grid
    Le problème, c'est qu'un peu plus tard, tu voudras sans doute écrire un parseur XML ou un système permettant de gérer les SVG (dessin vectoriel en format texte), et que tu auras donc aussi besoin d'une représentation arborescente.

    Le patron "composite" se présentera naturellement comme le meilleur patron pour y arriver, sauf que...

    Si tu fais dériver tes éléments de type "SVGItem" de Base, Node et Leaf (après tout : tous tes élément SVG sont des éléments d'une vue arborescente ), ton arborescence de classes va très rapidement devenir monolithique et impossible à gérer (cf, à ce sujet, cette discussion qui déchaîna les passions )

    De plus, il n'y a, a priori, aucune raison pour que tu puisses décider de faire cohabiter, dans une seule et même collection, aussi bien des éléments de type "graphique" et des élément de type "partie de SVG".

    Or, si tes 'SVGItem' dérivent effectivement des mêmes classes que tes éléments graphiques, tu auras la possibilité de faire ce genre d'aberration, sans aucun garde fou susceptible de te faire prendre conscience que tu fais quelque chose d'anormal.

    La solution serait donc de créer une nouvelle arborescence, toujours basée sur le patron composite, (SvgItem ?) qui pourrait ressembler à quelque chose comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
          /SvgLeaf----SvgLine
         /     \- SvgPoint
        /
    SvgItem--- SvgNode --- YYYYY 
                   \- XXXXX
    Soit, voilà une solution des plus correctes, mais bon...

    Le problème reste quand meme que le code de toutes les classes "abstraites" (Base / SvgItem, Leaf / SvgLeaf, Node /SvgNode) sera, au nom près, strictement dupliqué... avec tous les problèmes que cela peut sous entendre

    Et le problème se reproduira pour chaque série de classes pour lesquelles tu voudras envisager le patron "composite" (re ) !!!

    Le fait de travailler avec une version template te permet, dés le départ, d'éviter tous les écueils:

    En effet, ton code pourrait se limiter à une (et une seule !) implémentation du patron composite proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /* la base du patron composite */
    template <typename T>
    class CompositeBase
    {
        /*...*/
    };
    /* la classe "Feuille" */
    template <typename T>
    class Leaf : public CompositeBase<T>
    {
        /*...*/
    };
    /* la classe "Noeud" */
    template <typename T>
    class Node : public CompositeBase<T>
    {
        /*...*/
    };
    qui serait utilisée, pour chaque arborescence dont tu as besoin, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /* une interface de base propre à tes besoins */
    class AbstractInterface
    {
        /*...*/
    };
    /* une feuille concrète */
    class ConcreteLeaf : public Leaf<AbstractInterface>,
                         public AbstractInterface
    {
        /*... */
    };
    /* un noeud concret */
    class ConcreteLeaf : public Node<AbstractInterface>,
                         public AbstractInterface
    {
        /*... */
    };
    Tu éviteras donc aussi bien la duplication de code (et tous les problèmes que cela sous entend), que tous les problèmes liés à une arborescence de classes trop monolithique, le tout, pour un investissement sommes toutes assez faible.

    Ne crois tu pas que cela dépasse largement le cadre d'une "figure de style" destinée à "simplifier l'écriture de code"
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  10. #10
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Le problème reste quand meme que le code de toutes les classes "abstraites" (Base / SvgItem, Leaf / SvgLeaf, Node /SvgNode) sera, au nom près, strictement dupliqué... avec tous les problèmes que cela peut sous entendre
    Je pense que c'est là que nos avis divergent. Tout d'abord, la classe Base ne possède pas de code dupliqué, mais uniquement l'interface pas laquelle tu vas manipuler l'ensemble de ta hiérarchie, et est donc totalement dépendante de la hiérarchie considérée.

    La classe Leaf me semble ne même pas avoir besoin d'exister, et je fais généralement dériver directement mes classes Button, Label (à supposer qu'elles n'aient pas de filles, ce que je ne pense pas, et ce que d'autres que moi ne pensent pas non plus (voir WPF par exemple), mais il s'agit là d'un autre sujet) de Base, sans passer par un intermédiaire Leaf dont je ne vois pas très bien le rôle.

    La classe Node, elle, peut contenir une certaine duplication de code, la notion de conteneur de sous nœuds. C'est à mon avis sur elle, et elle seule (et encore, une seule partie d'elle, la partie conteneur), qu'on pourrait avoir envie d'écrire du code générique pour éviter la duplication. Et là aussi, je suis un peu dubitatif.

    De la même manière qu'il n'y a pas un seul conteneur dans la STL, il n'y a pas une seule manière de contenir des sous objets dans le pattern composite. Et la variabilité est encore plus grande. Il y a :
    - le choix du conteneur lui même (qui a lui seul introduit toute la variabilité de la STL),
    - le choix du mode de gestion de la durée de vie des sous objets, y compris lors d'une copie (partage de propriété, propriété unique et duplication des sous objets lors de la duplication du père (c'est souvent associé au pattern composite que j'ai trouvé l'utilité de l'idiome clone), système de copy-on-write)...
    - le choix de l'identification des éléments (s'ils sont connus par une chaîne de caractères (laquelle), par un id unique, ou si on se moque complètement de les identifier). Par exemple dans le composite répertoire/fichiers, cette identification par l'intermédiaire de chemins est fondamentale, dans le composite XML, cette identification plus floue se traduit par l’existence d'XPath, que je vois mal faire entrer dans un design générique...
    - et probablement d'autres axes de variabilité que je n'ai pas encore vu mais qui apparaîtraient si l'on tentait de pousser l'exercice jusqu'au bout.

    Alors, certes, on peut imaginer s'en sortir en faisant de cette classe une classe à base de politiques, mais la question que je me pose est : Est-ce que le jeu en vaut la peine. Parce qu'au final, gérer la partie conteneur de cette classe, c'est relativement peu de code en général (on ne fourni pas toute l'interface des collection, mais une interface réduite correspondant aux manipulations usuelles), et j'hésiterais fortement à remplacer ce code par une usine à gaz.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  11. #11
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    C'est un peu le problème avec tous les essais d'encapsulation des patterns. Soit ils n'encapsulent qu'une faible de la variabilité possible, et on se retrouve à ne pas s'en servir plus ou moins souvent, soit ils encapsulent beaucoup, et on se retrouve avec des usines à gaz.

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

Discussions similaires

  1. Pattern visiteur et template
    Par coda_blank dans le forum C++
    Réponses: 7
    Dernier message: 24/10/2011, 20h26
  2. Héritage (pattern Composite)
    Par Ploupi dans le forum Langage
    Réponses: 4
    Dernier message: 21/09/2011, 10h36
  3. Pattern Composite en C++
    Par snakico dans le forum Langage
    Réponses: 2
    Dernier message: 17/07/2010, 20h41
  4. Persistence d'un pattern "composite" avec JDO
    Par Yomhgui dans le forum Persistance des données
    Réponses: 1
    Dernier message: 21/12/2008, 22h20

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