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 en C++


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 2
    Par défaut Pattern Composite en C++
    Bonjour,

    je poste sur ce forum pour la première fois afin d'obtenir une réponse à mon problème. Je travaille actuellement sur une grammaire abstraite permettant de reconnaitre (par la voix) un langage. Je résume la situation:
    - Une grammaire possède plusieurs règles.
    - Une règle possède plusieurs items.
    - Un item peut-être (via héritage): un texte ou alors un noeud.
    - Un noeud peut-être (via héritage): une liste, une phrase ou une éventualité.
    - Un noeud possède la propriété de pouvoir posséder d'autres items.

    Ce problème semble donc plutôt bien disposer à être résolu via un pattern Composite. Je désire, à partir d'un Item, pouvoir remonter à sa règle directe ou son noeud direct. Je possède donc deux méthodes renvoyant des pointeurs sur la chose.

    L'idée est que l'utilisateur puisse créer une grammaire, ses règles, ses items, puis plus tard, récupérer un item et ajouter directement un item frère dans une liste par exemple. (En récupérant donc la règle mère OU le noeud père et en invoquant la méthode d'ajout d'item, le tout sans besoin de cast).

    Voici la classe Item:
    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
    25
    26
    27
    28
     
    class Item
    {
    public:
    	// returns name of item.
    	const std::wstring &getName() const;
    	// returns id of item.
    	unsigned long getID() const;
    	// returns mother rule of item (never NULL).
    	Rule *getRuleMother() const;
    	// returns father node of item (may be NULL).
    	Node *getnodeFather() const;
    	// returns true if item is a direct rule child
    	bool isRuleChild() const;
     
    protected:
    	// Constructors of an item. 
    	// CONS_1 ruleMother: pointer to the mother rule if item is direct child of a rule.
    	// CONS_2 nodeFather: pointer to the father node if item is direct child of a node.
    	Item(const std::wstring &name, unsigned long id, Rule *ruleMother);
    	Item(const std::wstring &name, unsigned long id, Node *nodeFather);
    	// Only an itemCreator can delete an Item.
    	friend void ItemCreator::freeItem(Item *item);
    	virtual ~Item() {}; 
    private:
    	Node *nodeFather;
    	Rule *ruleMother;
    };
    Et la classe Node:
    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
    25
    26
    27
    28
    29
    30
    31
     
    class Node: public Item
    {
    public:
    	unsigned long getNumberOfItems() const;
    	unsigned long getItems(std::vector<Item*> &result) const;
    	Item *getItem(unsigned long itemID) const;
     
    	// Item creation. Returns a pointer on created Item (never NULL).
    	// Constructors are available with and without name (empty name).
    	// text: text to recognize.
    	Text *createText(const std::wstring &name, const std::wstring &text);
    	Text *createText(const std::wstring &text);
    	Phrase *createPhrase(const std::wstring &name);
    	Phrase *createPhrase();
    	List *createList(const std::wstring &name);
    	List *createList();
    	Option *createOption(const std::wstring &name);
    	Option *createOption();
    	// deletes a direct item of a node. Returns true if operation is a success.
    	bool deleteItem(unsigned long itemID);
    protected:
    	Node(const std::wstring &name, unsigned long id, Rule *ruleMother, ItemRegistrar &registrar);
    	Node(const std::wstring &name, unsigned long id, Node *nodeFather, ItemRegistrar &registrar);
    	virtual ~Node(); // delete all items
    private:
    	Node(const Node &n);
    private:
    	ItemContainer items;
    	ItemCreator itemCreator;
    };
    Plusieurs remarques sur le code:
    - L'utilisation de pointeurs résulte du fait que je désire que le module que je développe soit cohérent et uniforme (je ne veux pas d'un get référence et d'un autre get pointeur).
    - La non utilisation de références provient du fait que je ne désire pas utiliser d'exceptions et que dans le cas d'une recherche, il est impossible de retourner une réference NULL.

    Pour l'instant, comme vous le remarquez, je possède un pointeur sur une classe fille dans la classe mère. Ceci parait étrange, et pourtant, ca me parait la solution la moins "pénible". De plus, ma classe Rule ne peut pas hériter d'Item, je perds alors l'application du pattern composite...
    Le pattern Composite peut être vu de deux façons:
    - La classe mère déclare les fonctions d'ajout et de récupération mais lance une exception par défaut. La classe feuille ne surcharge pas la méthode, mais la classe fille composite, si.
    - la classe mère ne possède pas les fonctions d'ajout et de récupération et il est nécessaire de downcaster le pointeur en classe fille.

    Je cherche une solution sans downcast, et pas crade de préférence .

    Une autre question est: Dans le cas où cette architecture est considérée comme Fixe (i.e., seul un Node peut posséder d'autres Items), est-ce un mal ABSOLU de parler d'une classe fille dans la classe mère ? (sachant que ca ne brise pas l'extension du code car il s'agira simplement d'hériter de la classe Fille si on veut ajouter un nouvel élement).

    Merci d'avance pour vos réponses .

    Pierrick

  2. #2
    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 snakico Voir le message
    Pour l'instant, comme vous le remarquez, je possède un pointeur sur une classe fille dans la classe mère. Ceci parait étrange, et pourtant, ca me parait la solution la moins "pénible".
    Ça ne me paraît pas étrange. Tu n'est pas dans le cas où tu développe une classe de base comme un point d'ouverture pour que plus tard on puisse définir n classes dérivées dont l'auteur initial n'as aucune idée du comportement. Tu es dans le cas où tu construits n classes reliées entre elles, et si un Item a besoin de connaître un Nœud, pourquoi s'en priver ?
    Citation Envoyé par snakico Voir le message
    De plus, ma classe Rule ne peut pas hériter d'Item, je perds alors l'application du pattern composite...
    D'après ce que j'ai compris, le pattern composite s'applique dans ton cas aux classes item, nœud, texte, liste, phrase, éventualité. Pas à Rule. Une Rule ne peut pas en contenir d'autres. Un item ne peut pas contenir de Rule. Donc là encore, je ne vois pas de soucis.
    Et à la base, je ne vois pas pourquoi tu voudrait faire dériver Rule d'Item. La seule chose que ces deux classes semblent avoir en commun, c'est qu'elles possèdent toutes deux des items, dans le cas où Item est un nœud. Si cette commonalité a besoin d'être factorisée, ça se fait de plusieurs façons (le choix entre ces manières de faire dépend du projet, que je ne connais pas assez), à partir d'une classe ItemContainer :
    - Si cette commonalité doit faire partie de l'interface, à la fois la classe Rule et la classe Nœud (mais pas la classe Item) dérivent publiquement de la classe ItemContainer.
    - Si cette commonalité n'est qu'un détail d'implémentation, Rule et Nœud en dérivent de manière privée, ou agrègent une variable membre de ce type.
    Citation Envoyé par snakico Voir le message
    Le pattern Composite peut être vu de deux façons:
    - La classe mère déclare les fonctions d'ajout et de récupération mais lance une exception par défaut. La classe feuille ne surcharge pas la méthode, mais la classe fille composite, si.
    Beark ! C'est la porte ouverte à plein d'erreurs à l'exécution.
    Citation Envoyé par snakico Voir le message
    - la classe mère ne possède pas les fonctions d'ajout et de récupération et il est nécessaire de downcaster le pointeur en classe fille.
    La troisième est que l'ensemble des classes ne soient utilisées que par leur interface commune, ou alors en connaissant leur type exact. Ce n'est pas toujours possible, mais on peut assez souvent s'en sortir, surtout l'arbre est créé d'un seul bloc, puis utilisé. Lors de la création, on sait quels sont les types exacts des objets manipulés, on peut donc utiliser toutes leurs fonctions membre sans problème. Ce n'est qu'après qu'ils se perdent dans la masse et ne peuvent plus être manipulés que par l'intermédiaire de leur classe de base.
    Le pattern visiteur permet aussi d'effectuer des traitements spécifiques sur ce genre d'arbre.
    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.

  3. #3
    Candidat au Club
    Profil pro
    Inscrit en
    Juillet 2010
    Messages
    2
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2010
    Messages : 2
    Par défaut
    Bonjour JolyLoic et merci de ta réponse.

    Je suis rassuré de voir qu'avoir une classe mère qui connait sa fille n'est pas une faute grave. Après avoir retourné le problème dans tous les sens, je ne vois de toute façon pas d'autre possibilité. Et de plus, comme tu le précises, la classe mère et fille sont les bases pour étendre cette grammaire, donc aucun problème.

    Je pense qu'à force d'entendre parler de design patterns, j'ai tenté d'en voir là ou il n'y en avait pas besoin. Ma classe Rule et Item factorisent le code de possession d'Item grâce à ItemContainer.

    Sur le choix de faire dériver Rule et item d'Item Container, je me suis posé la question, mais au final, ce n'est qu'un détail d'implémentation, et je préfère le cacher. (De plus, une classe Grammaire de plus haut niveau possède aussi des items mais ne peut pas les créer, donc cela simplifie le choix).

    Concernant le pattern composite, la solution à base d'exception me semble en effet, assez choquante. J'ai été étonné de la retrouver à plusieurs endroits sur le net. Le souci vient du fait que la relation de composition qui caractérise le Composite est parfois représenté à sens unique, ou à double sens, d'où la confusion.

    Enfin pour le parcours de l'arbre (je crée une grammaire XML pour la Speech API de windows), j'ai utilisé un pattern visiteur.

    Merci pour tes réponses .

    Pierrick

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

Discussions similaires

  1. Pattern composite : peut on faire les opérations suivantes
    Par bigbang84 dans le forum Design Patterns
    Réponses: 17
    Dernier message: 10/11/2012, 18h43
  2. Pattern Composite et templates
    Par ternel dans le forum Langage
    Réponses: 10
    Dernier message: 21/08/2012, 11h19
  3. Héritage (pattern Composite)
    Par Ploupi dans le forum Langage
    Réponses: 4
    Dernier message: 21/09/2011, 10h36
  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