Diagrammes de classes : modéliser la structure du code
À retenir — Un diagramme de classes décrit comment votre code est organisé : quelles classes existent, ce qu'elles contiennent (attributs et méthodes) et comment elles se relient (héritage, composition, association). C'est le plan d'architecture de votre orienté objet.
À quoi ça sert vraiment
Les deux chapitres précédents montraient du mouvement (un flux, un échange). Le diagramme de classes montre une structure figée : la forme de votre code orienté objet, indépendamment de ce qu'il fait à l'exécution. C'est l'outil pour expliquer une architecture, préparer un refactoring ou faire entrer une recrue dans une base de code.
classDiagram
class Utilisateur {
+int id
+string nom
+string email
-string motDePasse
+seConnecter() bool
+seDeconnecter() void
}
Une classe se déclare avec class, et son contenu va entre accolades : les attributs (données) et les méthodes (comportements, reconnaissables aux parenthèses).
La visibilité : qui peut accéder à quoi
Le symbole devant chaque membre indique sa visibilité, exactement comme en POO.
| Symbole | Visibilité | Signification |
|---|---|---|
+ |
public | accessible partout |
- |
privé | interne à la classe |
# |
protégé | accessible aux sous-classes |
~ |
package | accessible dans le paquet |
On peut aussi typer les attributs et les valeurs de retour, ce qui rend le diagramme directement exploitable comme spécification :
classDiagram
class CompteBancaire {
+string numero
-float solde
+deposer(float montant) void
+retirer(float montant) bool
+consulterSolde() float
}
:::tip[Type après le nom, façon UML]
Mermaid suit la convention UML : +deposer(float montant) void se lit « méthode publique deposer, prend un float montant, ne retourne rien ». Le type de retour se met après la parenthèse, pas devant. C'est l'inverse de Java/C# mais c'est la norme des diagrammes.
:::
Le cœur du sujet : les relations
Un diagramme de classes sans relations n'est qu'une liste. Tout l'intérêt est de montrer comment les classes se connectent. Mermaid distingue chaque type de lien par une flèche différente.
classDiagram
ClasseA <|-- ClasseB : héritage
ClasseC *-- ClasseD : composition
ClasseE o-- ClasseF : agrégation
ClasseG --> ClasseH : association
ClasseI ..> ClasseJ : dépendance
ClasseK ..|> ClasseL : réalisation
Le tableau à mémoriser — c'est la grammaire du diagramme :
| Syntaxe | Relation | Se lit |
|---|---|---|
| `A < | -- B` | héritage |
A *-- B |
composition | A est composé de B (B meurt avec A) |
A o-- B |
agrégation | A contient B (B survit à A) |
A --> B |
association | A utilise / connaît B |
A ..> B |
dépendance | A dépend de B ponctuellement |
| `A .. | > B` | réalisation |
:::warning[Composition vs agrégation : la nuance qui compte]
Le losange plein (*--, composition) signifie que la partie ne vit pas sans le tout : une Commande et ses LignesDeCommande — supprimez la commande, les lignes disparaissent. Le losange vide (o--, agrégation) signifie une appartenance plus lâche : une Equipe et ses Joueurs — dissolvez l'équipe, les joueurs existent toujours. Confondre les deux change le sens du modèle.
:::
Les cardinalités : combien de chaque côté
On précise combien d'instances participent à la relation, entre guillemets aux extrémités.
classDiagram
Client "1" --> "0..*" Commande : passe
Commande "1" *-- "1..*" LigneCommande : contient
Produit "1" --> "0..*" LigneCommande : figure dans
Les notations courantes : 1 (exactement un), 0..1 (zéro ou un), 1..* (un ou plusieurs), 0..* ou * (zéro ou plusieurs). On lit ici : « un client passe zéro à plusieurs commandes ; une commande contient une à plusieurs lignes ».
Interfaces, classes abstraites et énumérations
Les annotations entre <<...>> qualifient une classe.
classDiagram
class Forme {
<<interface>>
+aire() float
+perimetre() float
}
class Cercle {
+float rayon
+aire() float
}
class Rectangle {
+float largeur
+float hauteur
+aire() float
}
Forme <|.. Cercle
Forme <|.. Rectangle
class Statut {
<<enumeration>>
ACTIF
SUSPENDU
FERME
}
<<interface>>, <<abstract>>, <<enumeration>>, <<service>> : autant d'étiquettes qui clarifient le rôle de la classe sans changer la syntaxe.
:::example[Cas concret : un mini-modèle de blog] Voici une structure complète et réaliste, le genre de diagramme qui sert de référence partagée dans un projet.
classDiagram
class Auteur {
+int id
+string nom
+publier(Article a) void
}
class Article {
+int id
+string titre
+string contenu
+Date publieLe
+ajouterCommentaire(Commentaire c) void
}
class Commentaire {
+int id
+string texte
+Date creeLe
}
class Categorie {
+int id
+string nom
}
Auteur "1" --> "0..*" Article : écrit
Article "1" *-- "0..*" Commentaire : contient
Article "0..*" --> "1..*" Categorie : classé dans
:::
Notes et regroupements
Comme ailleurs, on peut annoter une classe :
classDiagram
class Cache {
+get(string cle) string
+set(string cle, string valeur) void
}
note for Cache "Implémentation Redis<br/>TTL par défaut : 3600 s"
Erreurs fréquentes
:::danger[Ce qui casse un diagramme de classes]
- Confondre le sens des flèches d'héritage : c'est
Parent <|-- Enfant(la pointe vers le parent), pas l'inverse. - Oublier
classDiagramen première ligne. - Mettre le type avant le nom de méthode façon Java : non, c'est
+methode() TypeRetour. - Espaces non gérés dans les noms de classe : préférez des noms sans espace (PascalCase). :::
En résumé
- Le diagramme de classes décrit une structure figée : classes, attributs, méthodes et relations.
- La visibilité se note
+public,-privé,#protégé,~package. - Les relations ont chacune leur flèche : héritage
<|--, composition*--, agrégationo--, association-->, dépendance..>, réalisation..|>. - Composition (losange plein) = la partie meurt avec le tout ; agrégation (losange vide) = appartenance lâche.
- Les cardinalités entre guillemets précisent le « combien » de chaque côté.
Au chapitre suivant, on garde l'idée de structure mais on la met en mouvement avec le diagramme d'états : comment un objet passe d'un état à un autre au fil des événements.