Outils pour utilisateurs

Outils du site


nsi:terminales:classes

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
nsi:terminales:classes [2021/06/23 18:00] goupillwikinsi:terminales:classes [2022/08/29 21:39] (Version actuelle) goupillwiki
Ligne 1: Ligne 1:
 ====== Classes - Programmation orientée objet (POO) ====== ====== Classes - Programmation orientée objet (POO) ======
  
-{{:langages:lisp_logo.png?nolink&50 |Lisp}}+{{nsi:langages:lisp_logo.png?nolink&50 |Lisp}}
  
-{{ :langages:java_logo.png?nolink&50|Java}}+{{ nsi:langages:java_logo.png?nolink&50|Java}} 
 + 
 +{{ :nsi:terminales:classes:classes.fiche.pdf |Fiche à imprimer}}
  
 Apparu en 1960 avec LISP. Très répandu aujourd'hui. En Java, //presque// tout est objet. Apparu en 1960 avec LISP. Très répandu aujourd'hui. En Java, //presque// tout est objet.
Ligne 25: Ligne 27:
 </WRAP> </WRAP>
  
-Pour le dire simplement, la POO permet d'organiser mieux le programme ce qui permet de faciliter le développement de gros programmes.+Dans l'[[classes_exo_preparation|exercice]] on rencontre les problèmes : 
 + 
 +  * Pas de façon simple pour regrouper toutes les données concernant le triangle, 
 +  * pas de façon simple de savoir qu'une variable contient un triangle, et un triangle bien formé, 
 +  * multiplication de fonctions en vrac. 
 + 
 +Les classes vont permettre de simplifier ces problèmes : 
 + 
 +  * La classe définit un modèle qui définit la façon de créer et d'utiliser des objets. Une classe ''Triangle'' permettra de définir exactement les données contenues dans un objet de ce type. 
 +  * Dès lors qu'un objet est de type ''Triangle'', on est certain qu'il respecte les contraintes qu'on a fixé dans la classe. 
 +  * Chaque classe définit ses propres méthodes de sorte que le code est mieux organisé. ''Triangle'' possède sa méthode ''aire'' qui ne pourra être confondu avec la méthode ''aire'' de ''Parallelogramme''.
  
 ===== Notion de classe ===== ===== Notion de classe =====
Ligne 35: Ligne 47:
  
 <WRAP tip> <WRAP tip>
-Cela rappelle la définition abstraite des structures de données -- [[liste_abstraite|Listes]], [[pile_abstraite|Piles]] et [[file_abstraite|Files]] -- consistant à préciser toutes les propriétés désirées. Une classe est une implémentation qui énonce naturellement les propriétés désirées.+Cela rappelle la définition abstraite des structures de données -- [[.structures:liste_abstraite|Listes]], [[.structures:pile_abstraite|Piles]] et [[.structures:file_abstraite|Files]] -- consistant à préciser toutes les propriétés désirées. Une classe est une implémentation qui énonce naturellement les propriétés désirées.
 </WRAP> </WRAP>
  
-===== Exercice : Exemple d'un module de géométrie =====+===== Définir une classe =====
  
-On souhaite faire des calculs de géométrie en 2D. Les points sont identifiés par leur coordonnées ''(x,y)'' dans un repère orthonormé. Tout ce qui suit sera dans un même programme.+==== Donner un nom ====
  
-=== Triangle ===+Une classe est identifiée par un nom. L'usage est d'utiliser la casse du chameau, [[https://fr.wikipedia.org/wiki/Camel_case|UpperCamelCase]].
  
-On souhaite travailler avec sur des triangles qui seront définies par les coordonnées de leurs 3 sommets et leur nom.+Par exemple : ''Triangle'', ''TriangleIsocele'', ''Losange'', ''PolygoneRegulier''
  
-  - Sous quel forme représenter le triangle dans le code ? +==== Identifier les attributs ====
-  - Donner la signature d'une fonction chargée de calculer l'aire d'un tel triangle. +
-  - Est-il possible de mal utiliser la fonction, c'est à dire de l'appeler avec autre chose qu'un triangle ou un triangle mal formé ?+
  
-=== Parallélogramme ===+Qu'est ce qui définit un objet ?
  
-On poursuit en ajoutant des parallélogrammesMême principe avec quatre sommets.+Un triangle sera défini par ses 3 sommetsSes attributs seront donc ces sommets. Mais sous quelle forme ? 
 +  * 6 variables pour les 3 paires de coordonnées ? 
 +  * un tableau contenant les 3 paires de coordonnées ? 
 +  * 3 objets ''Point'' que l'on devrait aussi définir ?
  
-  - Peut-on choisir les sommets comme on veut ? Que faut-il vérifier ? +On a le choix.
-  - Donner la signature d'une fonction chargée de calculer l'aire d'un parallélogramme.+
  
-=== Et encore... ===+==== Définir l'interface =====
  
-On souhaite poursuivre en ajoutant d'autres formes : losanges, rectangles, hexagones... et ajouter d'autres fonctions comme perimètre ou centre de gravité...+Comment agit on sur un objet depuis l'extérieur ?
  
-Quel problème rencontre-t-on ?+On doit bien sûr pouvoir le créer. Un objet aura toujours un **constructeur** qui est une méthode spéciale permettant de le créer -- notamment de réserver l'espace nécessaire en mémoire -- puis de l'initialiser.
  
-## Définir une classe+Et puis par exemple, pour un ''Triangle'', on voudra calculer son aire, son périmètre... Ce sont autant de méthodes que la classe devra posséder.
  
-Dans l'exercice on rencontre les problèmes :+==== Choisir la visibilité ====
  
-* Pas de façon simple pour regrouper toutes les données concernant le triangle, +<WRAP group> 
-pas de façon simple de savoir qu'une variable contient un triangleet un triangle bien formé, +<WRAP half column> 
-* multiplication de fonctions en vrac.+En général, les classes permettent de régler finement les éléments d'un objet qui sont accessibles depuis l'extérieur et ceux qui ne le sont pas. Mais ce n'est pas le cas en Python : En Pythontout est visible. Nous parlerons donc de visibilité au cours des exercices mais sans trop insister.
  
-Les classes vont permettre de simplifier ces problèmes :+Un élément accessible est dit **public**, s'il est inaccessible, il est dit **privé**.
  
-* La classe définit un modèle qui définit la façon de créer et d'utiliser des objets. Une classe `Triangle` permettra de définir exactement les données contenues dans un objet de ce type.+==== Diagramme UML ====
  
-* Dès lors qu'un objet est de type `Triangle`, on est certain qu'il respecte les contraintes qu'on a fixé dans la classe.+{{nsi:langages:uml_logo.png?nolink&100 |}}
  
-* Chaque classe définit ses propres fonctions de sorte que le code est mieux organisé.+Pour aider au développement et au travail de groupe, les informaticiens ont recours à différents types de diagrammes dont le but est de communiquer rapidement les choix effectués. Le UML -- Unified Modeling Language -- en fait partie.
  
-### Comment procéder+C'est un vaste domaine, nous allons rester simples.
  
-*Remarque :* par convention, le nom d'une classe utilise *CamelCase* : première lettre en majuscule, majuscule à chaque changement de mot : `Triangle`, `TriangleIsocele`... +> Les + signifient "public". Pour "privé", on aurait mis un - 
- +</WRAP> 
-On peut suivre les étapes suivantes : +<WRAP half column> 
-* Identifier les objets et leurs **attributs** : quelles sont les données caractérisant les objets + Triangle   ^
-* Identifier les opérations : comment utilise-t-on l'objet, notamment depuis l’extérieur ? +
-* Définir la **visibilité** : quels attributs / méthodes sont visibles par les autres ? +
-* Implémentation +
- +
-*On reviendra plus tard sur la notion de visibilité.* +
- +
-### Exercice 2 +
- +
-Reprenons le cas du triangle. +
- +
-* Quels sont ses attributs ? +
-* Quelles sont les opérations possibles ? +
- +
-Pour représenter ces choix de façons claire et explicite, on utilise un diagramme UML *Unified Modeling Language* +
- +
- Triangle   +
-|:------------- |+
 |**Attributs**| |**Attributs**|
 | + réel : x1 | | + réel : x1 |
Ligne 114: Ligne 109:
 | + réel : aire() | | + réel : aire() |
 | + réel : périmètre() | | + réel : périmètre() |
 +
 +//diagramme UML//
 +</WRAP>
 +</WRAP>
  
 Dans un programme complexe, le diagramme UML permettra d'indiquer les **dépendances** entre les différentes classes. Dans un programme complexe, le diagramme UML permettra d'indiquer les **dépendances** entre les différentes classes.
  
-## Classe en Python +==== Dépendance ====
- +
-Voici un modèle +
-</markdown> +
- +
-<file python triangle.py> +
-class Triangle: # on utilise PascalCase UpperCamelCase +
-    """ +
-    Commentaires utiles pour la lisibilité et la documentation +
-    """ +
-    x1: float # ceci n'est pas requis en Python +
-    y1: float # mais peut rendre le code plus clair +
-    x2: float +
-    y2: float +
-    x3: float +
-    y3: float +
-    nom: string +
- +
-    def __init__(self, x1, y1, x2, y2, x3, y3, nom): +
-        """ +
-        Constructeur - Gère l'initialisation de l'objet +
-        """ +
-        self.x1 x1 # x1 est la valeur fournie +
-                     # self.x1 est l'attribut x1 de l'objet +
-        self.y1 y1 +
-        # etc. +
- +
-    def aire(self) -> float : +
-        """ +
-        Documentation... +
-        -> float n'est pas requis en Python. Il permet seulement de préciser ce qui est +
-        attendu en sortie. +
-        """ +
- +
-        # formule de maths... +
-        return abs((self.x2 - self.x1)*(self.y3 - self.y1) - (self.y2 - self.y1)*self(x3 - self.x1))/+
- +
-    # puis les autres méthodes... +
-</file> +
- +
-<markdown> +
-**Exemple d'utilisation** +
- +
-```python +
-monTriangle Triangle(0,0,5,2,3,4,'T1'+
-monTriangle.aire() # retourne 7.0 +
-type(monTriangle)  # retourne Triangle, ce qui s'affiche <class : Triangle>  +
-``` +
- +
-### Instanciation +
- +
-`Parallelogramme` et `Triangle` sont des modèles. Quand on définit la *classe* `Triangle`, on ne crée aucun objet de type `Triangle`. On se contente de dire comment faire pour en créer un ou pour l'utiliser. +
- +
-Quand on écrit `monTriangle = Triangle(...)`, on crée un objet de type `Triangle`. +
- +
-On dit que `monTriangle` est une **instance** de la classe `Triangle`. +
- +
-> **Autrement dit :** On peut définir ce qu'est une voiture et comment on fait une voiture dans un livre. Ce livre n'en est pas pour autant une voiture. Quand on suit le livre et qu'on fabrique la voiture, on obtient une réalisation de voiture, c'est une **instance** de voiture. +
- +
-Une classe peut avoir plusieurs instances : on peut créer plusieurs objets `Triangle` en suivant le guide que constitue la classe `Triangle`. +
- +
-> **Autrement dit :** On peut fabriquer plusieurs voitures, identiques ou pas. +
- +
-### Exercice 3 +
- +
-* Dans un fichier `triangle.py` définissez la classe `Triangle` - **complétez** ce qui manque dans le modèle donné plus haut. +
-* En fin de fichier, ajoutez le code de test suivant et exécutez : +
- +
-```python +
-if __name__ == '__main__': +
-    monTriangle = Triangle(0,0,5,2,3,4,'T1'+
-    a = monTriangle.aire() +
-    p = monTriangle.perimetre() +
-     +
-    print("L'aire du triangle est de {}".format(a)) +
-    print("Le périmètre du triangle est de {}".format(p)) +
-``` +
- +
-### Très important : +
- +
-* L'instanciation `monTriangle = Triangle(...)` provoque l'exécution du **constructeur**. +
- +
-  En Python, il s'agit de la méthode `__init__(...)`  +
- +
-* En tant qu'objet de type `Triangle`, `monTriangle` a des attributs et des méthodes. +
-  * `monTriangle.x1` désigne l'attribut `x1̀ de `Triangle` +
-  * `monTriangle.aire` désigne la méthode `aire` de `monTriangle`. +
- +
-* Dans la signature et le corps de la méthode `aire`, on peut voire apparaître le mot-clé `self`. +
-  La méthode `aire` ne peut être appelée que via une **instance**, par exemple `monTriangle.aire()`. `self` désigne alors l'instance elle-même. +
- +
-```python +
-tA.aire() # dans ce cas, self = tA +
-tB.aire() # dans ce cas, self = tB +
-``` +
- +
-  D'autres langages préfèrent utiliser le mot-clé `this`. +
- +
-* En Python, **lors de la définition** de la méthode `aire`, on est obligé de préciser l'argument `self` en première position. +
- +
-  Au moment de l'appel, on ne précise pas `self`. On se contente de *par ex* `tA.aire()`, et `self` est automatiquement mis égal à `tA`. Tout se passe comme si on avait appelé `Triangle.aire(tA)`. +
- +
-#### L'objet est reponsable de l'action +
-Sans classe, on faisant `aireTriangle(triangle)` où `triangle` subissait la fonction passivement. +
- +
-Maintenant, `triangle` est un objet doté de méthodes et on écrit `triangle.aire()`. L'objet est **responsable** du calcul. +
- +
-Chaque type d'objet définit ses propres méthodes. Le code devient plus clair : `triangle.aire()`, `rectangle.aire()`. C'est léger, lisible, bien organisé. +
- +
-### Exercice 4 +
- +
-On peut considérer que le diagramme UML de la classe `Parallelogramme` est identique à ceci près qu'il faut ajouter un quatrième point. +
- +
-* Dans un fichier `parallelogramme.py` créez une classe `Parallelogramme` +
-* En fin de fichier, ajoutez le code de test suivant et exécutez : +
- +
-```python +
-if __name__ == '__main__': +
-    monPlg = Parallelogramme(0,0,5,2,8,6,3,4,'P1'+
-    a = monPlg.aire() +
-    p = monPlg.perimetre() +
-     +
-    print("L'aire du plg. est de {}".format(a)) +
-    print("Le périmètre du plg. est de {}".format(p)) +
-``` +
- +
-*On peut voir ici que le code est presque identique à celui du cas `Triangle`. Quand on appelle la méthode `aire()`, aucune confusion n'est possible. `monPlg` est un objet `Parallelogramme`, donc `monPlg.aire()` appelle la méthode `aire` de `Parallelogramme`.* +
- +
-* Que faudrait-il faire pour être certain qu'un objet `Paralllelogramme` soit toujours valide ? +
- +
-  *Comprendre : comment vérifier qu'il est valide au moment où on le crée et vérifier qu'il reste valide dans le cas où on modifie ses attributs.* +
- +
-#### Public / privé +
- +
-```python +
-plg = Parallelogramme(0,0,1,0,1,1,1,0,'P'+
-plg.x1 = 10 +
-``` +
- +
-Lors de la création `plg` est bien valide. Mais on modifie `plg.x1` de sorte qu'il ne l'est plus... +
- +
-Une solution est d'empêcher la modification de l'attribut `x1` (et des autres) en le rendant **privé**. +
- +
-Un attribut **privé** ne peut-être lu et modifié que depuis l'intérieur de la définition de la classe. +
- +
-*Remarque : En Python, il n'y a pas vraiment de gestion de l'accès public / privé. On convient de nommer les attributs / méthodes privé(e)s en les faisant précéder par `_`.* +
- +
-Dans l'exemple, ce serait donc `_x1`. +
- +
-Dans le diagramme UML, on mettra - au lieu de +. +
- +
-*Remarque : Certains invitent à utiliser `__` (deux underscore au lieu d'un). Ne vous y fiez pas trop. Ce choix crée des difficultés et ne constitue pas une protection.* +
- +
-*La notion public / privé n'est pas explicite dans le programme. Ne vous en souciez donc pas trop, on pourra travailler en ne considérant que rien n'est privé.* +
- +
-### Classes et sous-classes +
- +
-* **Éviter tout bloc de code trop compliqué  :** découper au maximum en fonctions. +
-* **Idem pour les classes  :**  Utiliser une classe spécifique pour tout type d'item. +
- +
-### Exercice 5 +
- +
-* Dans  un fichier `point.py`, définir une classe `Point` ayant les attributs `x`, `y`. +
-* Ajouter la méthode `distance(self, autrePoint)` de sorte que pour les `Point` `A` et `B`, l'expression `A.distance(B)` donne la distance `AB`. +
-* Modifier les classes `Triangle` et `Parallelogramme` pour qu'elles utilisent la classe `Point` au lieu des paires de coordonnées `x, y`. +
- +
- +
-### Important +
-```python +
->>> p1 = Point(2,3) +
->>> p2 = Point(2,3) +
->>> p1 == p2 # la réponse est False ! +
-``` +
- +
-Les deux points ont les mêmes coordonnées mais ce sont néanmoins deux points différents. +
- +
-En écrivant `Point(2,3)` on crée un **instance** en mémoire. Quand on réécrit `Point(2,3)` on crée une nouvelle instance en mémoire même si elle a les mêmes attributs. Ce sont donc deux instances différentes. +
- +
- +
-### Exercice 6 - problème de dépendance +
- +
-Supposons que l'on veuille ajouter une fonction qui détermine si un point est contenu dans un triangle. Selon vous, quel est le meilleur choix ? +
- +
-* dans la classe `Point`, définir la méthode `estDansTriangle(self, triangle)` +
-* dans la classe `Triangle`,  définir la méthode `contientPoint(self, point)` +
-* en dehors des deux classes, définir une fonction `triangleContientPoint(triangle, point)` +
- +
-### Dépendance en UML +
-Le diagramme UML permet de faire apparaître que la classe `Triangle` utilise la classe `Point`. +
-</markdown> +
- +
-{{ :nsi:terminales:umltrianglepoint.png?nolink&400 |}} +
- +
-<markdown> +
-###Méthodes magiques +
- +
-Quand on définit `x = 5` et `y 12`, on peut faire avec `x` et `y` un certains nombres d'opérations qui seront comprises automatiquement par le langage. +
- +
-* On peut additionner `x + y` +
-* On peut comparer `x <y` +
-* On peut afficher `print(x)`, ce qui provoque le **transtypage** de `x`, `int -> str` +
- +
-Si on souhaite pouvoir faire ce genre d'opérations avec notre objet, c'est possible ! +
- +
-Le cas le plus courant est l'affichage. On aimerait que le transtypage `str(monPoint)` produise une chaîne de caractère comme `(15 ; 45)` pour le point de coordonnées `x 15` et `y 45`. +
- +
-Il faut utiliser la méthode `__str__(self)` +
- +
-```python +
-# Dans la classe Point +
-def __str__(self): +
-    """ +
-    transtypage -> str +
-    """ +
-    return "({} ; {})".format(self.nom, self.x, self.y) +
-``` +
- +
-### Exercice 7 +
- +
-Ajoutez une fonction de transtypage vers `str` dans la classe `Triangle`. +
- +
-Pensez à tester. +
- +
-### Exercice 8 +
- +
-* Proposez une implémentation pour les **piles** en utilisant des classes. +
-* Même chose pour les **files**. +
-* Dans les deux cas, prévoyez une méthode `__str__` +
- +
- +
-### Exercice 9 ++ +
- +
-On peut aller plus loin en ajoutant des vecteurs, en définissant le produit scalaire... +
- +
-### Exercice 10 ++ +
-</markdown>+
  
-[[classe_relation_exercice|Implémentation d'une relation (BDD) avec les classes]]+Supposons que l'on crée une classe ''Point'' pour gérer les points et qu'alors ''Triangle'' utilise cette classe. On peut faire apparaître clairement la dépendance sur le diagramme UML.
  
 +{{ nsi:terminales:classes:umltrianglepoint.png?nolink&400 |}}
nsi/terminales/classes.1624464009.txt.gz · Dernière modification : de goupillwiki