Aller au contenu

UML : diagramme de classes

Le diagramme de classes décrit les classes du domaine, leurs attributs et opérations, et les relations entre elles. C’est le diagramme central d’UML, et celui qui sert à concevoir la base de données.

┌──────────────────────────────┐
│ Client │ ← nom
├──────────────────────────────┤
│ - numClient: int │ ← attributs
│ - nom: String │
│ + email: String │
│ # adresse: String [0..1] │
├──────────────────────────────┤
│ + passerCommande(): Commande │ ← opérations (méthodes)
│ + changerEmail(e: String) │
└──────────────────────────────┘
Compartiment Contenu
Nom Substantif au singulier, majuscule initiale
Attributs visibilité nom: type [multiplicité] = valeurParDéfaut
Opérations visibilité nom(paramètre: type): typeRetour

Les compartiments d’attributs et d’opérations sont facultatifs : pour modéliser une base, on ne garde souvent que les attributs.

Symbole Sens En TypeScript
+ public public
- privé private / #champ
# protégé protected
~ paquet (module)

Voir POO : encapsulation et héritage.

┌──────────┐ 1 0..* ┌────────────┐
│ Client │───────── passe ───────>│ Commande │
└──────────┘ └────────────┘

Lecture : « Un client passe zéro à plusieurs commandes ; une commande est passée par un client » (la multiplicité du côté de Client est 1, celle du côté de Commande 0..*).

Multiplicité Sens
1 Exactement un
0..1 Zéro ou un (facultatif)
* ou 0..* Zéro à plusieurs
1..* Un à plusieurs
2..5 Entre 2 et 5

Autres éléments d’une association :

Élément Rôle
Nom Verbe (passe, contient)
Sens de lecture (> près du nom) Précise la lecture
Navigabilité (flèche) Quelle classe connaît l’autre : Client ──> Commande signifie que le client peut accéder à ses commandes
Rôles Nom donné à une extrémité (manager, subordonné)

Quand une association porte des attributs (cas du « plusieurs à plusieurs ») :

┌────────────┐ 1..* 0..* ┌────────────┐
│ Commande │─────────────────────────│ Article │
└────────────┘ │ └────────────┘
│
┌─────────┴───────────┐
│ LigneCommande │
├─────────────────────┤
│ quantite: int │
│ prixUnitaire: Money │
└─────────────────────┘

La classe d’association LigneCommande (reliée à l’association par une ligne pointillée) porte quantite et prixUnitaire. C’est l’équivalent de l’association porteuse de propriétés de Merise ; elle devient une table associative. On peut aussi en faire une classe ordinaire reliée aux deux autres par deux associations 1—0..* : la table obtenue est la même.

Relation Sens Symbole Cycle de vie
Association Lien simple ligne Indépendants
Agrégation « fait partie de » (faible) losange vide Les parties existent sans le tout
Composition « est composé de » (forte) losange plein Les parties disparaissent avec le tout
┌────────────┐ ◆───────────── 1..* ┌─────────────────┐
│ Commande │ │ LigneCommande │ composition : une ligne
└────────────┘ └─────────────────┘ n'existe pas sans sa commande

La composition se traduit par une clé étrangère avec ON DELETE CASCADE (la suppression du tout supprime les parties) ; l’agrégation et l’association simple par RESTRICT ou SET NULL. L’agrégation est rarement utile : on l’utilise peu, la composition et l’association suffisent.

┌───────────────┐
│ Personne │
├───────────────┤
│ nom │
│ email │
└───────┬───────┘
△
┌───────────┴───────────┐
┌─────────┴──────┐ ┌───────┴────────┐
│ Client │ │ Employe │
├────────────────┤ ├────────────────┤
│ adresseFacture │ │ poste │
│ pointsFidelite │ │ dateEmbauche │
└────────────────┘ └────────────────┘

Le triangle vide pointe vers la classe parente. Contraintes possibles : {complete} / {incomplete} (toute personne est-elle forcément client ou employé ?), {disjoint} / {overlapping} (peut-on être les deux ?), notées dans des accolades près du triangle. Même signification que T/X/P de Merise (MCD avancé). La traduction en tables a trois stratégies (voir Des classes à la base de données).

«interface»
Notificateur ┌────────────────────┐
┌────────────────┐ │ «abstract» Forme │ nom en italique ou stéréotype
│ envoyer(...) │ │ aire(): double │
└───────△────────┘ └────────────────────┘
┆ réalisation (pointillé + triangle vide)
┌───────┴────────────┐
│ NotificateurSms │
└────────────────────┘
Élément Symbole
Interface Stéréotype «interface»
Réalisation (implements) Flèche pointillée à triangle vide
Classe abstraite Nom en italique ou {abstract}
Dépendance (« utilise ») Flèche pointillée simple

Voir POO : polymorphisme et interfaces.

┌───────────────────────┐
│ Article │
├───────────────────────┤
│ reference: String {id}│
│ prix: Money {>= 0} │
│ stock: int {>= 0} │
└───────────────────────┘
┆
[note : le prix courant ; la ligne de commande garde le prix payé]

Les contraintes s’écrivent entre accolades {…} (ou en OCL, un langage formel) ; les notes (rectangle au coin replié) ajoutent des explications sans modifier le modèle. Les règles de gestion importantes y ont leur place.

┌─────────────────┐ 1 0..* ┌──────────────────┐
│ Client │──────── passe ───────│ Commande │
├─────────────────┤ ├──────────────────┤
│ numClient │ │ numCommande │
│ nom │ │ dateCommande │
│ email │ │ statut │
│ adresse │ ├──────────────────┤
└─────────────────┘ │ total(): Money │
└────────┬─────────┘
│ 1..*
│ (classe d'association)
┌────────┴─────────┐ 0..* ┌────────────────┐
│ LigneCommande │──────│ Article │
├──────────────────┤ ├────────────────┤
│ quantite │ │ reference │
│ prixUnitaire │ │ libelle │
└──────────────────┘ │ prix │
│ stock │
└────────────────┘

Source PlantUML correspondante (voir Outils et PlantUML) :

@startuml
class Client {
- numClient: int
- nom: String
- email: String
- adresse: String
}
class Commande {
- numCommande: int
- dateCommande: DateTime
- statut: Statut
+ total(): Money
}
class Article {
- reference: String
- libelle: String
- prix: Money
- stock: int
}
class LigneCommande {
- quantite: int
- prixUnitaire: Money
}
Client "1" -- "0..*" Commande : passe
Commande "1" *-- "1..*" LigneCommande
Article "1" -- "0..*" LigneCommande
@enduml
class Client {
readonly commandes: Commande[] = [];
constructor(
public readonly numClient: number,
public nom: string,
public email: string,
public adresse: string,
) {}
}
class LigneCommande {
constructor(
public readonly article: Article,
public readonly quantite: number,
public readonly prixUnitaire: number,
) {}
}
class Commande {
readonly lignes: LigneCommande[] = []; // composition : créées et détruites avec la commande
constructor(
public readonly client: Client,
public statut = 'nouvelle',
) {}
total(): number {
return this.lignes.reduce((t, l) => t + l.quantite * l.prixUnitaire, 0);
}
}

Association 1—0..* : Commande.client (obligatoire) et, si la navigation est utile, Client.commandes. Voir POO : classes et objets.

  • Modéliser le domaine (concepts métier), pas des détails techniques.
  • Nommer classes (noms) et associations (verbes) avec le vocabulaire des utilisateurs.
  • Toujours indiquer les multiplicités.
  • Limiter les méthodes dans le diagramme de classes d’une base (les attributs suffisent).
  • Préférer la composition et l’association à l’héritage (POO : composition et patrons).
  • Un diagramme par domaine (clients, commandes, stock).
Symptôme Piste
Multiplicités placées du mauvais côté La multiplicité se place près de la classe opposée (inverse de Merise)
Association « plusieurs à plusieurs » avec des attributs Classe d’association ou classe intermédiaire
Hiérarchie d’héritage profonde Aplatir, interfaces, composition
Diagramme avec 30 classes Découper par paquets / domaines
Hésitation agrégation ou composition Utiliser la composition si la partie meurt avec le tout, sinon association simple
Attributs qui sont des classes (adresse de type Adresse) Fine si Adresse a une identité propre ou plusieurs attributs : relation vers la classe

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune.