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:47] 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 45: 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>
  
Ligne 85: Ligne 87:
 ==== Diagramme UML ==== ==== Diagramme UML ====
  
-{{:langages:uml_logo.png?nolink&100 |}}+{{nsi:langages:uml_logo.png?nolink&100 |}}
  
 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. 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.
Ligne 114: Ligne 116:
 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.
  
-===== Implémentation Python ===== +==== Dépendance ====
- +
-==== Syntaxe ==== +
- +
-<code python linenums> +
-class NomDeLaClasse: +
-    """ +
-    commentaires décrivant à quoi sert la classe +
-    """ +
-    x:float   # un exemple d'attribut. ":float" pas obligatoire en Python +
-    n:int = 0 # autre exemple, initialisé à 0 +
-     +
-    def __init__(self, w): +
-        """ +
-        méthode spéciale utilisée lors de la création d'un objet +
-        pour initialiser cet objet +
-        """ +
-     +
-    def une_fonction(self, a, b, c): +
-        """ +
-        Notez l'attribut spécial self qui désigne l'objet lui-même +
-        """ +
-        self.x # "self" désigne l'objet, ".x" désigne l'attribut x de cet objet +
- +
-c = NomDeLaClasse(14) # création d'un objet respectant le modèle définit par la classe +
-c.x # désigne l'attribut x de l'objet c +
-</code> +
- +
-==== Instanciation ==== +
- +
-Une classe définit un modèle. Quand on utilise ce modèle pour réaliser un objet concret, on parle d'instanciation. L'objet est une instance du modèle. +
- +
-Par exemple, nous sommes des instances du concept abstrait "Humain". Nous avons toutes les caractéristiques qui font un Humain et pourtant nous sommes différents. La classe définit les attributs à posséder mais pas la valeur de ces attributs. +
- +
-==== self ==== +
- +
-La classe définit le comportement d'un objet. Quand on a besoin de désigner l'objet dont on parle, en Python, on utilise ''%%self%%''. Beaucoup de langages préfèrent ''%%this%%'' mais c'est le même principe. +
- +
-Toutes les méthodes ordinaires d'une classe Python ont comme premier argument ''%%self%%''+
- +
-> Il existe des méthodes spéciales qui fonctionnent autrement. +
- +
- +
- +
- +
-<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> +
- +
- +
-**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`. +
- +
- +
- +
- +
-### 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>+
  
 +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.1624466853.txt.gz · Dernière modification : de goupillwiki