Considérons l'exemple suivant : On souhaite proposer un outil capable d'évaluer la valeur d'une maison à partir de critères propres comme la superficie, l'adresse, le nombre de pièces ou encore la présence d'un jardin.
En considérant simplement ces 4 critères, on se rend vite compte qu'il existe une infinité de combinaisons possibles donnant toutes des maisons différentes.
Si l'on se place dans le contexte de la Programmation Orientée Objet (POO), l'utilisation d'une classe Maison est toute indiquée. La classe fera office de moule de base duquel pourra sortir une pléthore de maisons différentes.
Commençons par visualiser cette classe grâce à une représentation graphique empruntée à l'UML1, langage que l'on utilisera par la suite pour faire des diagrammes de classes et représenter les relations qui existent entre les différentes classes d'un projet. Ici on commence avec une seule classe et donc un diagramme de classes très sobre.Fig. 1 - Représentation UML de la classe Maison et de ses attributs
Cette représentation graphique nous apporte toutes les informations nécessaires à l'implémentation de la classe.Rappel sur les types de base du langage C#
L'équivalent de ce diagramme de classes en C# est :Maison.cs
Pour pouvoir manipuler cette classe, il nous faut un autre fichier contenant une méthode statique Main qui sera appelée au moment de l'exécution de notre projet. On crée donc un nouveau fichier Program.cs et on complète sa méthode Main par la déclaration et l'instanciation d'une nouvelle instance de Maison ainsi que quelques affichages en console.
En savoir plus sur les méthodes et variables statiques
Program.cs
On a maintenant tout ce qu'il faut pour pouvoir compiler et exécuter notre projet.
Fig. 2 - Résultat en console de l'exécution du projet ExemplePOO
Sans trop de surprise, on se rend compte que chaque attribut de l'objet UneMaison, est initialisé à sa valeur par défaut : la valeur null pour Adresse, 0 pour Superficie et NbPieces et false pour Jardin. Si on regarde de plus près le constructeur de la classe Maison, qui est la méthode de même nom : Maison(), on se rend bien compte qu'il ne dispose d'aucune consigne à appliquer lors de la création d'un nouvel objet, donc par défaut : on retrouve les valeurs par défaut. Plutôt instinctif.
En savoir plus sur les valeurs par défaut des types en C#
Reprenons notre code. On souhaite maintenant pouvoir instancier des objets Maison différents et améliorer l'affichage en console.
On ajoute donc dans la classe Maison des instructions pour la construction des objets. On complète pour ça le constructeur de la classe en spécifiant qu'un objet Maison peut être construit seulement à partir des informations suivantes : une adresse, une superficie, un nombre de pièce et la présence ou non d'un jardin. On définit ainsi le moule global et chaque objet maison pourra être différent en utilisant des informations différentes pour chacun de ces champs. Ils sont maintenant obligatoires à la construction d'un objet Maison (il n'y a plus de constructeur par défaut).
Maison.cs
On adapte ensuite la méthode Main de notre projet pour tester notre classe Maison avec ses nouveaux paramètres. On va donc déclarer et instancier 3 objets à partir de la classe Maison mais avec des attributs différents. On retrouve le mot clé new qui permet de faire appel à un constructeur de classe et donc de spécifier quel moule on souhaite utiliser pour construire notre objet.
On crée ensuite une structure de données de type liste pour regrouper nos 3 nouveaux objets Maison. Il est intéressant ici d'utiliser ce type de structure de données car il nous offre de nombreuses méthodes pour interagir avec lui, comme par exemple ici une méthode de parcours des données utilisée via le mot clé foreach. Cette boucle nous permet de mettre en place un affichage générique faisant appelle aux spécificités de chaque objet en les manipulant tour à tour.
Program.cs
Fig. 3 - Résultat en console de l'exécution du projet ExemplePOO
Revoir les différences entre tableaux et listes en C#
En savoir plus sur l'opérateur ternaire "?" en C#
Maintenant que l'on obtient un catalogue de maisons, on va pouvoir s'attaquer au coeur du problème : Fournir un moyen d'évaluer la valeur d'une maison en fonction des 4 critères connus : Adresse, Superficie, NbPieces et Jardin.
Dans le monde de la POO, la réponse à cette question correspond à l'implémentation d'une méthode, c'est-à-dire une fonction spécifique à la classe, unique dans sa définition mais sensible aux attributs de la classe et donc fournissant des résultats potentiellement différents en fonction des instances sur lesquelles elle est appelée.
Reprenons notre classe Maison pour lui ajouter une méthode publique EvaluationValeur() qui aura comme retour un entier flottant correspondant à la valeur évaluée de la maison. Profitons-en pour substituer la méthode ToString() de la classe Maison et ainsi généraliser le formatage de l'affichage en console des informations concernant un objet Maison. Ces informations n'ont en effet pas leur place dans la méthode Main. On les récupère et on les remet à leur place dans la méthode d'affichage de la classe Maison elle-même.
En savoir plus sur la substitution de la méthode ToString
Maison.cs
Program.cs
Fig. 4 - Résultat en console de l'exécution du projet ExemplePOO
En savoir plus les expressions régulières en C#
Exemples d'utilisation des expressions régulières
Prenez le temps de bien lire et comprendre le fonctionnement de la méthode EvaluationValeur(). Celle-ci permet de déterminer la valeur de la maison en multipliant sa superficie par un facteur calculé par la méthode. Initialement ce facteur vaut 3000, il représente le prix par défaut au metre carré. Il est ensuite adapté en fonction des informations de la maison :
Cette méthode repose sur l'utilisation d'expressions régulières, n'hésitez pas à suivre la ressource précédente si cette notion ne vous est pas familière. Ces expressions régulières vont nous permettre de rechercher des motifs précis dans une chaine de caractères. Ici on souhaite augmenter le prix d'une maison si le mot Paris ou le mot Lyon est contenu dans son adresse dans l'idée d'adapter le prix en fonction des villes les plus peuplées. Dans un soucis de simplicité, l'outil mis en place n'a pas tout à fait le résultat attendu, sauriez-vous dire pourquoi ?
Maintenant que nous avons ajouté quelques améliorations à notre classe initiale, il est temps de compléter sa représentation UML pour que le diagramme de classes coïncide avec l'implémentation. On complète donc le diagramme de classes en lui ajoutant les deux nouvelles méthodes ToString() et EvaluationValeur().
Fig. 5 - Représentation UML de la classe Maison, de ses attributs et de ses méthodes
On observe ainsi la représentation standard d'une classe dans le standard UML : Le nom de la classe en premier, ses attributs avec leurs niveaux d'accès et leurs types ensuite et, enfin, ses méthodes avec également leurs niveaux d'accès, leurs types de retour et leurs paramètres (autrement dit leurs signatures).
TO DO : Prenez le temps de bien comprendre chaque ligne de cet exemple, que ce soit la fonction Main ou la classe Maison. N'hésitez pas à les manipuler et les modifier vous même. Prenez également le temps de faire le lien entre l'implémentation et la représentation UML associée.
TO DO : En vous inspirant de l'exemple fourni, proposez une implémentation répondant au diagramme de classes suivant. Vous êtes libre sur l'implémentation des méthodes tant qu'elles utilisent les attributs de classe et qu'elles respectent les signatures2 imposées par le diagramme de classes. Entrainez-vous en créant un répertoire Git associé à cet exercice et en faisant des commits réguliers.
Fig. 6 - Représentation UML de la classe Terrain, de ses attributs et de ses méthodes
TO DO : Discutez entre vous des implémentations possibles de la classe Terrain.