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 :

Avis sur la conception d'un projet c++


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut Avis sur la conception d'un projet c++
    Bonjour à tous,
    je voudrais avoir votre avis sur la conception d'un projet :
    Les fichiers :

    Pour l'histoire, il s'agit d'un petit projet donné en L3 Info. Les auteurs du sujet sont donnés sur le pdf.

    Pour ce à qui n'ont pas voulu lire le pdf
    "Le but du projet est de modéliser un mode animal, c’est à dire voir les intéractions entre les trois
    éléments du monde : les carnivores mangent les herbivores et les herbivores mangent l’herbe. Pour
    construire un monde animal, il est nécessaire de savoir sur quel continent on se trouve. En Amérique,
    les carnivores sont les loups et les herbivores les bisons, tandis qu’en Afrique ce sont les lions et les
    girafes."

    La classe MondeAnimal

    La classe MondeAnimal est la classe principale de notre simulation. Nous déclarons une instance de cette classe en lui passant le continent sur lequel nous voulons réaliser la simulation, et nous appelons ensuite la méthode run.
    La classe MondeAnimal contient une grille de pointeurs sur des FauneFlore. (FauneFlore est une interface pour les classes Animal et Vegetal, nous la décrivons en détail dans le paragraphe suivant).


    Creator et Runner :

    Nous avons également défini deux autres classes dans le même fichier, car celles-ci sont des outils nécessaires au fonctionnement de MondeAnimal.
    La première est la classe Runner. Il s’agit d’un foncteur qui est utilisé dans la méthode run de MondeAnimal. Nous avons créé cette classe pour pouvoir utiliser l’algorithme for_each de la STL dans la méthode run.
    Il permet d’appeler pour chaque case la grille la méthode run. Le constructeur prend en paramètre un MondeAnimal par référence car la méthode run d’un FauneFlore modifie le MondeAnimal.

    Le deuxième foncteur, Creator, permet de créer des FauneFlore en appelant les méthodes de fabrication du Continent passé en paramètre dans le constructeur de Creator.
    Creator contient donc des pointeurs de méthodes sur la classe Continent. Cela nous permet de remplir la grille aléatoirement. Creator est donc lui aussi un foncteur qui renvoie un pointeur sur un FauneFlore.
    La grille est alors simplement remplie avec l’algorithme generate de la STL, et le Creator passé en paramètre.
    A noter la syntaxe de la déclaration d’un pointeur sur une méthode :
    typedef FauneFlore*(Continent::* FauneFloreCreator)()const;
    et l’appel de la méthode :
    (continent_.*creator_[random_])();
    Avec creator_ qui contient l’adresse des méthodes de fabrication.
    Les méthodes de la classe MondeAnimal sont les suivantes :
    • void affiche() const; permet d’afficher la grille, le nom des espèces est centré
    • void run(const size_t nbIter = 1); permet de lancer la simulation nbIter fois
    • void supprime(const size_t cle); supprime l’élément à l’indice clé, un Animal appelle cette méthode lorsqu’il mange quelque chose
    • inline void setEspace(const size_t espace); défini le nombre de caractères sur lequel nous affichons l’espèce d’un animal, il faut que ce nombre soit supérieur à la longueur maximale des espèces
    • inline size_t getTaille() const; renvoie la taille d’un côté de la grille
    • inline FauneFlore * operator[](const size_t cle); renvoie le FauneFlore d’indice cle
    • inline const FauneFlore * operator[](const size_t cle) const; renvoie le FauneFlore d’indice cle
    • inline void echange(const size_t pos1, const size_t pos2); échange le contenu des cases en appelant swap de la STL, nécessaire pour le déplacement des animaux


    La classe FauneFlore

    FauneFlore est la classe mère de tous les animaux et végétaux. Elle nous permet d’avoir un conteneur de pointeurs sur la classe mère, et donc d’appeler les méthodes des « vraies classes » par le polymorphisme.

    getArticle, getType, getName sont des méthodes qui permettent respectivement de retourner l’article (ie : le, la, une), le type (ie : herbivore, carnivore, vegetal), et le nom de l’espèce (ie : lion, loup, …).
    findCaseVide permet de trouver s’il existe une case vide autour de l’animal, et find permet de trouver de la nourriture se trouve dans une case voisine. Pour find, nous passons le type (ie : vegetal, carnivore, herbivore) en paramètre.
    Nous avons bien sûr la méthode run qui ne fait rien pour le Vegetal. Pour Carnivore et Herbivore, elle teste si l’animal peut manger, si oui, l’animal mange, sinon il se déplace (s’il peut).



    Il n'y a pas les classes Continent, Amerique, Afrique car elles ne sont pas très compliquées. TLogfile permet juste de sauvegarder dans un fichier les différents évènements.



    Les problèmes de notre conception sont :
    1. la duplication de la méthode run, en effet juste une chose varie entre les 2
    2. la méthode type() et getType() qui sont vraiment pas top


    1. La duplication de la méthode run a été obligée car nous pour un herbivore nous cherchons de l'herbe autour, alors que pour un carnivore nous cherchons un herbivore. A part ceci c'est le même code.

    2. Nous avons utiliser la méthode getType pour forcer les classes filles a implémenter cette méthode et pour faire des "méthodes virtuelles statiques".
    Nous utilisons type pour trouver un animal avec la méthode find.

    J'aimerais donc savoir si nous aurions pu éviter les deux points précédents. Le premier peut être résolu de la maniére suivante :
    j'implémente la méthode run dans Animal, et je crée un méthode regime virtuelle pure qui dit ce qu'un Animal mange et find appelle cette méthode.
    Il y a peut-être mieux, non ?

    Je voudrais également savoir, imaginons que j'ai 5 000 animaux. Est-ce qu'il pourrait-être intéressant de faire un pattern stratégie pour la méthode run (ie le comportement d'un animal) ?

    N'hesiter pas a faire des remarques sur la conception même si elle a été beaucoup guidée.

    Merci d'avance.

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    La classe MondeAnimal contient une grille de pointeurs sur des FauneFlore. (FauneFlore est une interface pour les classes Animal et Vegetal, nous la décrivons en détail dans le paragraphe suivant).
    Pourquoi des pointeurs ? T'alloues dynamiquement des types dérivés pour pouvoir stocker ça de manière uniforme ? (ce qui d'ailleurs n'est pas nécessaire)
    Dans ce cas, tu n'as pas des problèmes d'exception safety ?
    Tu n'as d'ailleurs pas vraiment précisé qui avait la charge de gérer les différentes ressources.

    La première est la classe Runner. Il s’agit d’un foncteur qui est utilisé dans la méthode run de MondeAnimal. Nous avons créé cette classe pour pouvoir utiliser l’algorithme for_each de la STL dans la méthode run.
    Un simple bind aurait suffit.

    Il permet d’appeler pour chaque case la grille la méthode run. Le constructeur prend en paramètre un MondeAnimal par référence car la méthode run d’un FauneFlore modifie le MondeAnimal.
    Le monde ne devrait-il pas être disponible sous forme de singleton ou autre truc du genre plutôt ?

    Le deuxième foncteur, Creator, permet de créer des FauneFlore en appelant les méthodes de fabrication du Continent passé en paramètre dans le constructeur de Creator.
    Creator contient donc des pointeurs de méthodes sur la classe Continent. Cela nous permet de remplir la grille aléatoirement. Creator est donc lui aussi un foncteur qui renvoie un pointeur sur un FauneFlore.
    La grille est alors simplement remplie avec l’algorithme generate de la STL, et le Creator passé en paramètre.
    A noter la syntaxe de la déclaration d’un pointeur sur une méthode :
    typedef FauneFlore*(Continent::* FauneFloreCreator)()const;
    et l’appel de la méthode :
    (continent_.*creator_[random_])();
    Avec creator_ qui contient l’adresse des méthodes de fabrication.
    Mouais, ça me parait pas top.

    void affiche() const = 0; permet d’afficher la grille, le nom des espèces est centré
    Pourquoi la fonction est pure ?
    Il y a une histoire d'héritage de monde ?

    inline void setEspace(const size_t espace); défini le nombre de caractères sur lequel nous affichons l’espèce d’un animal, il faut que ce nombre soit supérieur à la longueur maximale des espèces
    Quel intérêt de limiter ça ? Utilise std::string.

    inline FauneFlore * operator[](const size_t cle); renvoie le FauneFlore d’indice cle
    inline const FauneFlore * operator[](const size_t cle) const; renvoie le FauneFlore d’indice cle
    Ne serait-il pas mieux de retourner des références ?

    Elle nous permet d’avoir un conteneur de pointeurs sur la classe mère, et donc d’appeler les méthodes des « vraies classes » par le polymorphisme.
    Pourquoi la classe contient des pointeurs ?

    getArticle, getType, getName sont des méthodes qui permettent respectivement de retourner l’article (ie : le, la, une), le type (ie : herbivore, carnivore, vegetal), et le nom de l’espèce (ie : lion, loup, …).
    getType est déjà fourni par le RTTI.

    Je croyais aussi qu'une FauneFlore avait une fonction membre run ?

  3. #3
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Merci loufoque de t'être penché sur le problème.

    Pourquoi des pointeurs ? T'alloues dynamiquement des types dérivés pour pouvoir stocker ça de manière uniforme ? (ce qui d'ailleurs n'est pas nécessaire)
    Dans ce cas, tu n'as pas des problèmes d'exception safety ?
    Tu n'as d'ailleurs pas vraiment précisé qui avait la charge de gérer les différentes ressources.
    MondeAnimal crée les objets et les detruits. Donc, les ressources sont seulement gérées par MondeAnimal. Pourquoi des pointeurs et non des objets ?
    Lorsqu'un Carnivore mange un Herbivore je le détruis.

    Un simple bind aurait suffit.
    Non car :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void Runner::operator()(FauneFlore * fauneFlore)
    {
        if (fauneFlore != 0)
            fauneFlore->run(monde_, indice_);
        ++indice_;
        indice_ %= taille_;
    }
    monde_ est la référence sur le MondeAnimal et indice, c'est l'indice sur la case de la grille.

    Le monde ne devrait-il pas être disponible sous forme de singleton ou autre truc du genre plutôt ?
    Non je ne pense pas, nous pouvons lancer des simulations sur différents mondes. Sinon je pourrais limiter à 5 le nombre d'instances pour les 5 continents et là ça rejoint ce que tu as dis.

    Quel intérêt de limiter ça ? Utilise std::string.
    Tu as pensé que je limitais le nombre de caractères de la chaine ?
    Non, en fait c'est pour le setw. Cela me permet d'avoir un affichage centré et pour cela je dois avoir une valeur plus grande dans le setw que la longueur max d'une chaine.

    Pourquoi la classe contient des pointeurs ?
    Non pas la classe FauneFlore mais MondeAnimal oui.
    C'est juste pour dire pourquoi j'ai rajouter une classe FauneFlore.

    getType est déjà fourni par le RTTI.
    Je croyais aussi qu'une FauneFlore avait une fonction membre run ?
    Oui, on est d'accord, je ne teste pas avec le type pour savoir quel méthode j'appelle.
    Mais si j'ai une grille 2x2 :
    -------------
    Lion | Girafe |
    -------------
    rien | Herbe |
    -------------
    Je voudrais que Girafe avec la méthode find cherche de l'herbe et si elle en trouve la mange.
    De même le Lion avec la méthode find cherche une Girafe et s'il en trouve la mange.
    Cela sans changer la méthode find définit dans la classe Animal.
    Sinon je pourrais faire dynamic_cast à la place de mon getType pour savoir si c'est le bon truc que j'attends.
    Car là je ne vois pas comment le RTTI peut m'aider.

    Je mets le lien dans le 1er post vers le code source dans quelques minutes.

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Par défaut
    dynamic_cast est implémenté grâce au RTTI.

  5. #5
    Membre confirmé Avatar de b Oo
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    179
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2004
    Messages : 179
    Par défaut
    Autant pour moi.
    Si je veux éviter un dynamic_cast il suffit que je définisse une méthode qui fait ce que j'attends ?
    C'est plus "beau" de faire une nouvelle méthode qu'un dynamic_cast non ?

    Sinon pour Creator tu n'aimais pas trop ça, tu vois quelque chose d'autre ?

    Merci encore.

  6. #6
    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 b Oo
    Autant pour moi.
    Si je veux éviter un dynamic_cast il suffit que je définisse une méthode qui fait ce que j'attends ?
    C'est plus "beau" de faire une nouvelle méthode qu'un dynamic_cast non ?
    Pourquoi serait-ce plus beau ?

    Ce qui est "moche" dans le dynamic_cast, ce n'est pas le dynamic_cast, c'est de devoir faire un traitement spécifique à une classe dérivée particulière, sans pouvoir encapsuler ce traitement dans une fonction virtuelle de cette classe. A partir du moment où tu as décidé que c'est ce que tu voulais faire, autant utiliser un outil tout fait pour le faire.

    D'autant plus que dynamic_cast a l'avantage de marcher avec des hiérarchies sur plus de deux niveaux, ce qui n'était pas le cas de la plupart des fonctions bricolées pour le remplacer que j'ai pu rencontrer. J'entends pas là, si C dérive de B qui dérive de A, tu as un A* qui pointe sur un objet de type C. Un dynamic_cast en B* de ce pointeur sera un succès, ce qui est une bonne chose. Un test de type monA->getType()==B::GetTypeName() échouera.

    Un cas où je pourrait voir l'intérêt de faire ce genre de chose, c'est si le type n'est pas directement lié à la hiérarchie de classe. Par exemple, dans une hiérarchie mammifères/oiseaux/reptiles, tu pourrait être tenté d'utiliser le RTTI pour implémenter une fonction indiquant si un animal pond des oeufs. Jusqu'au jour où tu rencontres un ornithorynque.
    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.

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

Discussions similaires

  1. Avis sur une conception de projet
    Par sabri_icone dans le forum UML
    Réponses: 3
    Dernier message: 01/06/2009, 18h56
  2. Besoin d'avis sur la conception d'un jeu
    Par MonsieurHelmut dans le forum Développement 2D, 3D et Jeux
    Réponses: 13
    Dernier message: 14/03/2007, 20h14
  3. [Méthodes]Votre avis sur ce concept sans nom
    Par Hibou57 dans le forum Méthodes
    Réponses: 6
    Dernier message: 17/04/2006, 19h38
  4. Avis sur la conception d'un projet
    Par Daniel MOREAU dans le forum Modélisation
    Réponses: 4
    Dernier message: 16/02/2006, 09h58
  5. Avis sur la conception de ma base de données.
    Par perlgirl dans le forum Décisions SGBD
    Réponses: 1
    Dernier message: 10/11/2005, 21h47

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