Gratuit · Sans inscription · Compatible fichiers .mmd

Éditeur de diagramme de classes Mermaid

Un diagramme de classes montre des types et leurs relations : ce qui contient quoi, ce qui hérite de quoi, ce qui dépend de quoi. Il convient quand la forme du code est le sujet — un modèle de domaine, une interface d'extension, un arbre d'héritage. Si vous voulez montrer ce qui se passe à l'exécution plutôt que la façon dont les types s'emboîtent, prenez un diagramme de séquence.

Un modèle de domaine de paiement

Trois types de relations en un seul diagramme : la composition pour les parties qui ne survivent pas au tout, l'héritage pour la hiérarchie des moyens de paiement, et une association ordinaire avec une multiplicité. Ici le sens est porté presque entièrement par les flèches ; les boîtes de classes sont presque accessoires.

classDiagram
    class Commande {
        +String reference
        +EtatCommande etat
        +Montant total()
        +void ajouterLigne(Article a, int quantite)
    }
    class LigneDeCommande {
        +Article article
        +int quantite
        +Montant sousTotal()
    }
    class MoyenDePaiement {
        <<abstract>>
        +autoriser(Montant montant) bool
    }
    class CarteBancaire {
        +String quatreDerniers
        +autoriser(Montant montant) bool
    }
    class VirementSepa {
        +String iban
        +autoriser(Montant montant) bool
    }
    class PrelevementAutomatique {
        +String mandatRum
        +autoriser(Montant montant) bool
    }

    Commande "1" *-- "1..*" LigneDeCommande : contient
    Commande --> MoyenDePaiement : réglée par
    MoyenDePaiement <|-- CarteBancaire
    MoyenDePaiement <|-- VirementSepa
    MoyenDePaiement <|-- PrelevementAutomatique
Ouvrir dans l'éditeur
Publicité

Exemples commentés

1. Une classe

`+` est public, `-` privé et `#` protégé. Un membre suivi de parenthèses est dessiné comme une méthode ; sans parenthèses, c'est un attribut.

classDiagram
    class Utilisateur {
        +String courriel
        -String empreinteMotDePasse
        +bool verifier(String candidat)
    }
Ouvrir dans l'éditeur

2. Héritage et interfaces

`<|--` est l'héritage, à lire « celui de droite étend celui de gauche ». L'annotation `<<interface>>` est une étiquette et non un comportement, mais c'est elle qui rend le diagramme lisible.

classDiagram
    class Depot {
        <<interface>>
        +chercher(String id) Entite
        +enregistrer(Entite e) void
    }
    class DepotPostgres {
        -Connexion connexion
        +chercher(String id) Entite
        +enregistrer(Entite e) void
    }
    class DepotEnMemoire {
        -Map stockage
        +chercher(String id) Entite
        +enregistrer(Entite e) void
    }
    Depot <|.. DepotPostgres
    Depot <|.. DepotEnMemoire
Ouvrir dans l'éditeur

3. Composition contre agrégation

La différence est la durée de vie. Le losange plein (`*--`) signifie que la partie meurt avec le tout : supprimez la facture et ses lignes disparaissent. Le losange creux (`o--`) signifie que la partie survit de son côté.

classDiagram
    class Facture {
        +String numero
    }
    class LigneFacture {
        +String libelle
    }
    class Client {
        +String raisonSociale
    }
    Facture "1" *-- "1..*" LigneFacture : composée de
    Client "1" o-- "0..*" Facture : a émis
Ouvrir dans l'éditeur

4. Génériques

Les tildes donnent les paramètres de type : `Depot~Utilisateur~`. L'imbrication fonctionne aussi, ce qui est parfois nécessaire et rarement une bonne idée. Les accents passent sans problème dans un générique.

classDiagram
    class Depot~T~ {
        +chercher(String id) T
        +tous() List~T~
    }
    class Cache~K, V~ {
        +obtenir(K cle) V
        +deposer(K cle, V valeur) void
    }
    class DepotUtilisateurs {
        +chercherParCourriel(String courriel) Utilisateur
    }
    Depot~Utilisateur~ <|-- DepotUtilisateurs
Ouvrir dans l'éditeur

5. Notes et direction

`direction LR` place le diagramme de gauche à droite, ce qui convient d'ordinaire mieux à un arbre d'héritage que la disposition par défaut. Une note est le bon endroit pour la contrainte qui ne tient pas dans une boîte de classe.

classDiagram
    direction LR
    class JournalDEvenements {
        +ajouter(Evenement e) void
        +rejouer(String flux) List~Evenement~
    }
    class Instantane {
        +int version
        +byte[] contenu
    }
    JournalDEvenements --> Instantane : écrit tous les 100 événements
    note for JournalDEvenements "En ajout seul. Les événements ne sont jamais modifiés ni supprimés."
Ouvrir dans l'éditeur

Référence de syntaxe du diagramme de classes

Les flèches de relation sont la partie qui mérite d'être apprise par cœur : ce sont elles qui distinguent un diagramme de classes d'un dessin de boîtes et de traits, et elles se lisent de droite à gauche d'une façon qui surprend longtemps.

SyntaxeSignification
classDiagramOuvre le diagramme. Sensible à la casse.
class Nom { ... }Classe avec ses membres. L'accolade fermante va sur sa propre ligne.
+membrePublic.
-membrePrivé.
#membreProtégé.
+methode(Type arg) TypeRetourUne méthode — ce sont les parenthèses qui en font une.
<<interface>> / <<abstract>>Stéréotype, écrit en première ligne dans la classe.
A <|-- BHéritage : B étend A.
A <|.. BRéalisation : B implémente l'interface A.
A *-- BComposition : B ne survit pas à A.
A o-- BAgrégation : B peut exister sans A.
A --> BAssociation orientée.
A ..> BDépendance — A utilise B sans le détenir.
A "1" --> "0..*" B : libelléMultiplicité à chaque extrémité et libellé de relation.
class Depot~T~Paramètre de type générique.
note for A "texte"Note attachée à une classe.
direction LRChange la direction du placement.
Publicité

Erreurs qui cassent un diagramme de classes

Reproduites avec Mermaid 11.12.2. Le diagramme de classes est plus indulgent que la plupart des types traités ici : plusieurs de ces erreurs se dessinent tranquillement et vous donnent la mauvaise image.

Ce que vous voyez

Parse error, se terminant par : got 'EOF_IN_STRUCT'

Pourquoi

Un corps de classe ouvert par `{` et jamais fermé. Pour une fois le nom du jeton aide vraiment : il signifie que le fichier s'est terminé alors qu'on était encore dans une classe.

Correction

Fermez l'accolade sur sa propre ligne.

Cassé
classDiagram
    class Commande {
        +String reference
Corrigé
classDiagram
    class Commande {
        +String reference
    }

Ce que vous voyez

Parse error, se terminant par : got 'ANNOTATION_END'

Pourquoi

Une flèche de diagramme de séquence employée dans un diagramme de classes. `->>` n'a aucun sens ici, et l'analyseur y entre assez loin pour produire un nom de jeton déroutant.

Correction

Utilisez une relation de classes : `-->` pour une association, `<|--` pour un héritage, `*--` pour une composition.

Cassé
classDiagram
    Commande ->> Client
Corrigé
classDiagram
    Commande --> Client : appartient à

Ce que vous voyez

No diagram type detected matching given configuration

Pourquoi

Mauvaise casse du mot-clé. `classdiagram` n'est pas `classDiagram`.

Correction

Mettez le D en majuscule.

Cassé
classdiagram
    class Commande
Corrigé
classDiagram
    class Commande

Ce que vous voyez

La flèche pointe dans le sens contraire de ce que vous vouliez

Pourquoi

Les flèches de relation se lisent depuis la pointe vers l'arrière. `A <|-- B` signifie que B hérite de A, et non l'inverse. Écrite à l'envers, elle se dessine quand même : elle affirme simplement que votre classe de base étend sa propre sous-classe.

Correction

Lisez « l'extrémité éloignée étend l'extrémité pointue ». Mettez le parent à gauche de `<|--`.

Cassé
classDiagram
    CarteBancaire <|-- MoyenDePaiement
Corrigé
classDiagram
    MoyenDePaiement <|-- CarteBancaire

Ce que vous voyez

Un attribut apparaît là où vous attendiez une méthode

Pourquoi

Les parenthèses sont la seule chose qui distingue une méthode d'un attribut. `+enregistrer` est un attribut nommé enregistrer ; `+enregistrer()` est une méthode. Les deux sont valides, donc rien ne vous prévient.

Correction

Ajoutez les parenthèses, puis le type de retour derrière si vous voulez le voir affiché.

Cassé
classDiagram
    class Depot {
        +enregistrer
        +chercher
    }
Corrigé
classDiagram
    class Depot {
        +enregistrer(Entite e) void
        +chercher(String id) Entite
    }

Ce que vous voyez

Composition et agrégation se ressemblent au premier coup d'œil et disent le contraire

Pourquoi

`*--` et `o--` diffèrent d'un caractère et codent une vraie différence de sens : la partie peut-elle survivre au tout. Employer la mauvaise produit un diagramme techniquement bien formé et factuellement faux sur votre domaine.

Correction

Losange plein `*--` quand supprimer le parent supprime l'enfant. Creux `o--` sinon.

Cassé
classDiagram
    Commande o-- LigneDeCommande : contient
Corrigé
classDiagram
    Commande *-- LigneDeCommande : contient

Notes sur le rendu

Mesuré sur le Mermaid 11.12.2 qu'utilise ce site.

C'est le type qui grandit le plus vite en hauteur

Mesuré avec des classes à deux membres enchaînées par héritage : trois classes donnent un viewBox d'environ 176×548, quarante classes donnent 180×7726, soit environ 194 pixels de hauteur par classe, la croissance la plus raide des six types du site. Un diagramme de quarante classes dépasse les sept mille pixels de haut et devient inutilisable comme image unique. `direction LR` aide, mais au-delà d'une quinzaine de classes, la solution honnête est de découper le diagramme par domaine métier.

Le nombre de membres n'influe presque pas sur la largeur

La largeur est dictée par la signature de membre la plus longue, non par leur nombre. Une classe à vingt attributs courts n'est pas plus large qu'une classe à trois. Autrement dit : soyez généreux en membres et avare en classes, ce qui est exactement l'inverse de l'instinct. En français les signatures sont plus longues qu'en anglais, si bien que la largeur se joue souvent sur une seule méthode au nom descriptif.

Les accents et les apostrophes passent partout

Vérifié : `référence`, `empreinteMotDePasse` ou `JournalDEvenements` fonctionnent comme noms de classes et de membres, et les accents passent aussi à l'intérieur d'un générique. Inutile de dépouiller le modèle de ses accents pour qu'il se dessine. La seule vraie restriction vient du tilde, qui est de la syntaxe.

Les génériques utilisent des tildes, avec une conséquence

`Depot~T~` existe parce que les chevrons entreraient en collision avec le HTML des étiquettes. Cela implique aussi qu'un tilde littéral dans un nom de classe ou de membre sera lu comme le début d'un paramètre de type. C'est rare, mais franchement déroutant quand cela arrive.

Les étiquettes sont du HTML, donc l'export PNG redessine

Les étiquettes de classes sont dessinées dans un `<foreignObject>` du SVG, que les navigateurs refusent de rasteriser sur un canvas. L'export PNG de ce site échouait auparavant en silence et rendait un fichier SVG ; il redessine désormais d'abord le diagramme avec des étiquettes en texte SVG simple. Le PNG est correct et à taille réelle, avec une typographie très légèrement différente de celle de l'écran.

Quand un autre diagramme convient mieux

Si vous documentez une base de données et non un système de types, prenez un diagramme ER. La distinction compte : les diagrammes de classes modélisent le comportement et l'héritage, que les tables n'ont pas, et les diagrammes ER modélisent correctement les clés et les cardinalités, ce que les diagrammes de classes escamotent.

Si le diagramme se réduit à des boîtes reliées par `-->` sans aucun membre, ce que vous dessinez est une architecture et non un diagramme de classes. Un organigramme avec des sous-graphes sera plus beau et affirmera moins de choses.

Et si la liste des classes est générée depuis le code, demandez-vous si le diagramme ne devrait pas l'être aussi. Un diagramme de classes tenu à la main pour une base de code qui change chaque semaine est faux au bout d'un mois, et un diagramme faux coûte plus cher que pas de diagramme du tout.

Autres types de diagrammes

Écrit par Dominik Malsch · Dernière mise à jour:

Ouvrir l'éditeur →