seance2_4h.md
-
Derrode Stéphane authoredDerrode Stéphane authored
Sommaire
TD2 : Modélisation de formes géométriques
Nous allons aborder dans ce TD le concept d'héritage de la programmation objet, et l'utilisation de tests unitaires pour guider le développement logiciel et améliorer sa qualité.
Le but de ce TD est de concevoir un module pour manipuler des formes géométriques avec Python. Ce module sera utilisé dans les TDs suivants, donc les tests seront essentiels pour limiter les éventuels bugs. Vous commencerez par définir les classes et leurs attributs, puis par écrire les tests unitaires de votre module, et terminerez par l'implémentation des méthodes.
Modélisation avec UML (1h)
Les formes géométriques sont représentées par des classes, et l'héritage sera utilisé pour factoriser les propriétés communes. Nous nous limitons à un repère à deux dimensions orthonormé, avec les axes croissant vers la droite et le bas. Les coordonnées dans ce repère sont des entiers relatifs (c'est-à-dire possiblement négatifs). Dans cet espace, nous choisissons de représenter les formes suivantes :
- Les rectangles caractérisés par leur origine (
x
,y
) et leurs dimensions (l
,h
). - Les ellipses caractérisées par leur origine (
x
,y
) et leurs rayons aux axes (rx
,ry
). - Un type de forme de votre choix (ex. triangle, polygone, étoile, ...), qui possède au moins une origine (
x
,y
).
Exercice 1 - Représentez les 3 classes dans un diagramme de classes UML (voir https://app.diagrams.net pour dessiner en ligne, avec l'onglet UML sur la gauche de l'interface). Il est recommandé de commencer les noms des classes par une majuscule et les attributs par une minuscule. Les attributs devraient-ils être publics ou privés ?
Les attributs x
et y
étant partagés par les trois classes, on introduit l'héritage pour les regrouper. Toutes les formes géométriques hériteront d'une même classe Forme. L'intérêt de cette classe est double :
- Du point de vue des développeurs du module, les méthodes dont le code est identique entre formes (ex. translation) sont fusionnées dans Forme, réduisant la quantité de code à produire (et donc la multiplication des erreurs possibles).
- Du point de vue des utilisateurs du module, on peut écrire du code qui manipule des rectangles et des ellipses (p. ex. système de collisions de formes) sans avoir à écrire du code séparément pour les rectangles et les ellipses. Cet aspect sera illustré dans un prochain TD.
Exercice 2 - Mettez à jour le diagramme UML en incluant la classe Forme et les relations d'héritage. Seuls les attributs seront inclus pour le moment.
Enfin, on vous demande de supporter a minima pour chaque forme les méthodes suivantes :
-
deplacement(dx, dy)
, qui effectue une translation selon un vecteur donné. -
contient_point(x, y)
, qui renvoieTrue
si et seulement si le point donné est à l'intérieur de la forme ou sur sa frontière. -
redimension_par_points(x0, y0, x1, y1)
, qui redimensionne la forme pour faire correspondre sa boîte englobante avec celle représentée par les points donnés.
Exercice 3 - Complétez le diagramme UML avec ces méthodes. Les constructeurs devront également être renseignés (méthode __init__
en Python), ainsi que les méthodes d'affichage (méthode __str__
en Python).
Exercice 4 - Écrivez un squelette de code correspondant à votre diagramme UML, dans un fichier formes.py. Seuls les constructeurs devront être implémentés. À l'intérieur des autres méthodes, vous mettrez l'instruction pass
de Python (qui ne fait rien mais vous rappelle que le code est inachevé).
Tests unitaires (1h)
Il convient à présent de rédiger des tests, qui échoueront tant que chaque fonction ne sera pas implémentée et correcte. Dans la méthodologie Test Driven Development, on les écrit toujours avant le code, au début ils échouent tous, et à mesure de l'avancement du projet le nombre de tests passés avec succès augmente. Nous utiliserons le module pytest présenté en cours.