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 :
- la duplication de la méthode run, en effet juste une chose varie entre les 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.
Partager