Le diagramme de classes : introduction
L'aspect statique (au sens description) du système est représenté par le diagramme de classes qui permet de modéliser les classes et leurs relations.
Sommaire
1) Notion d'objet
a) Attributs des objets
b) Comportement, messages
c) Identité
2) Notion de classe
a) Représentation
b) Retour sur les messages
c) Statuts des attributs et opérations
3) Relation entre classes
a) Relation de dépendance
b) Relation d'association
1) L'association porte un nom
2) Rôles dans les associations.
3) Cardinalités
4) Association porteuses d'attributs
5) Classe-association.
6) Arité supérieure à 2.
c) Agrégation et composition
1) Agrégation
2) Composition
d) Généralisation/spécialisation.
1) Généralisation multiple.
2) Classe abstraite.
3) Quelques écueils à éviter
e) Navigabilité
f) Classe interface
Le monde qui nous entoure est constitué d'objets. Une voiture, le livre qui est sur la table, le film que l'on vient d'aller voir. Par définition, un objet est unique, un livre identique à celui qui est sur la table est un autre livre.
Un objet est caractérisé par un état et des comportements.
Un livre comporte un nombre de pages, un poids, un titre... Cela traduit l'état de l'objet à tout moment. Une personne a une taille, un poids, une couleur de peau... Ces attributs sont susceptibles de changer de valeur, le poids d'une personne évolue sans cesse. Certains attributs par contre ne verront pas leurs valeurs évoluer, la couleur de la peau par exemple.
Les valeurs des attributs permettent de connaître
l'état d'un objet.
1.b Comportement des objets, messages
L'objet n'est pas seulement une somme d'informations, l'objet réagit. Cela n'est possible que s'il est muni d'opérations - actions- qui seront déclenchées en réponse à des sollicitations extérieures - d'un autre objet -. On traduit ce processus en introduisant la notion de message ; la réception d'un message va engendrer la réaction de l'objet. Bien sûr il faut que l'objet possède dans son comportement une action capable de traiter le message.
Ainsi un train peut recevoir des messages stopper, ralentir, accélérer, des actions spécifiques seront déclenchées, par contre le message voler sera rejeté.
Un objet est représenté par un rectangle, son
nom est souligné.
Le message a un nom, un émetteur, et un destinataire.
A noter que le nom du message correspond en général au nom de
l'action qui va être déclenchée par l'objet récepteur du message, néanmoins
il faut avoir à l'esprit qu'il s'agit de deux processus différents
: un objet reçoit un message et réagit par l'exécution
d'une action.
Cette distinction est bien visible dans les langages événementiels.
Ainsi un bouton qui reçoit un événement Click - message
- va réagir en exécutant le code qui se trouve dans la méthode
Click des boutons.
Le comportement d'un objet est ainsi la somme de ses actions.
Si un objet déclenche une action, cela peut produire une modification de son état, ainsi l'action "Accélérer" va modifier la valeur de son attribut "vitesse". De même l'état d'un objet influence son comportement, le message "Stopper" ne sera pas accepté si l'état de l'attribut "en marche" est à faux.
Nous avons vu qu'un objet est unique, il a donc une identité ; la notion d'identifiant ne relève pas du domaine de l'analyse mais de celui de l'implémentation - réalisation- . Bien sûr rien n'interdit de faire figurer un attribut, comme un numéro de SS, mais simplement par souci de description de l'objet et non d'identification.
Si la notion d'objet est le point de départ, il est nécessaire d'imaginer un niveau conceptuel qui permette de regrouper les objets selon le comportement et l'état. Ainsi une classe va rassembler les objets de même nature.
2.a Représentation d'une classe.
Exemple :
Un objet est une instance d'une classe.
unTrain
: Train
Après son instanciation l'objet bénéficie des opérations et des attributs de sa classe.
unTrain.Ralentir();
Interprétons l'envoi par un conducteur d'un message Stopper en direction d'un train:
class train{
...
void stopper(){
...; vitesse = 0;}
};
class conducteur{
...
train leTrain;
ArreterLeTrain(){
leTrain.Stopper();}
};
Un conducteur envoie le message Stopper à
son train, mais c'est de la responsabilité du train de s'arrêter, de
plus le conducteur n'a pas besoin de savoir comment le train s'arrête. Les objets
des deux classes communiquent à l'aide de messages, chaque objet de classe
traitant les messages qu'il reçoit.
2.c Statuts des attributs et opérations
L'encapsulation représente un des concepts fondamentaux du monde objet. Par principe même, on ne peut accéder aux attributs ou opérations d'un objet en dehors de ceux explicitement déclarés publics par la classe. Ainsi une classe n'est utilisable qu'au travers son interface - ensemble des attributs et opérations publics -. Ceci garantit l'intégrité des objets en les protégeant de toute modification d'état en dehors d'opérations explicitement définies.
Ainsi une recommandation forte impose de ne pas déclarer les attributs publics.
Un troisième statut est le mode protégé, accessibilité seulement pour la hiérarchie descendante de la classe.
La nouvelle
représentation devient :
Légende
- privé
+ public
# protégé
3. Les relations entre classes.
Les classes ne valent que par les relations qu'elles tissent entre elles. Cette phase est décisive dans l'élaboration du diagramme de classes. Mais c'est à partir des interactions entre les objets que doivent se dessiner les relations entre classes.
3.a Relation de dépendance.
C'est la relation la moins contraignante entre les classes. Elle est unidirectionnelle et définie une relation d'utilisation.
Dans une collaboration d'objets, cela correspond à l'envoi de message paramétré par un objet d'une autre classe.
Soit la situation suivante où différents articles
sont stockés dans différents entrepôts.
Diagramme d'objets
Remarque : si la classe de chaque objet est clairement identifiée, nous pouvons représenter des objets anonymes, comme instance de classe ; dans ce cas le nom de l'objet est remplacé par une instance. Le diagramme suivant a la même sémantique.
Diagramme d'objet
3.b.1 L'association porte un nom
Au niveau
des classes, nous pouvons construire une association. Une association relie
des classes dont les instances sont sémantiquement liées. Une
association ne sous-entend aucune hiérarchie dans la relation.
Diagramme
de classe
L'association a un nom "Est stocké", le symbole ">" indique seulement un sens de lecture.
L'association
suivante est équivalente car elle concerne les mêmes couples d'objets.
Diagramme
de classe
Remarque : nous utilisons une forme verbale pour qualifier le nom de
l'association.
3.a.2 Les classes jouent un rôle dans l'association
Le nom de l'association traduit la nature du lien entre les objets de classes : " Les lits sont stockés dans l'entrepôt de Montreuil". On peut être amené à préciser le rôle que joue chaque classe dans l'association, ici il s'agit des rôles de "gardien" côté entrepôt et "gardé" côté article.
Mais la
notion de rôle prend tout son sens lorsqu'un couple de classe est relié
par deux associations sémantiquement distinctes.
3.a.3 Les associations comportent des cardinalités.
Cette notion est identique à celle contenue dans Merise. Dans UML, on parle de valeurs de multiplicité.
Exemple 1
Interprétation : Une oeuvre donne lieu à 0 ou n livres. Un livre est issu d'une et une seule oeuvre.
Commentaires
- Le positionnement des multiplicités est inverse de la modélisation
française entité/association (modèles ango-saxons)
- La multiplicité 0..* est parfois traduite par simplement le symbole
*
Exemple 2
Interprétation : Une revue est disponible dans un ou plusieurs points de vente. Un point de vente distribue de une à plusieurs revues.
Commentaire : le nombre de classes participant à l'association définissent l'arité de l'association. Les deux exemples précédents montrent une association d'arité 2. Ceci sera le plus fréquent.
Valeurs de multiplicité
1..1 | Un et un seul |
1 | Un et un seul |
0..1 | Zéro ou un |
m..n | De m à n |
* | De zéro à plusieurs |
0..* | De zéro à plusieurs |
1..* | D'un à plusieurs |
3.a.4 Association porteuses d'attributs.
L'association
entre deux classes peut elle- même posséder des attributs. Par exemple
:
" Un homme peut avoir été marié plusieurs fois, et réciproquement,
les dates et lieus des mariages nous importent. "
Les attributs
"date" et "lieu" ne concernent pas seulement chaque instance des deux
classes mais des couples d'instances. Dans ce cas l'association va jouer à
la fois le rôle d'association et le rôle de classe, on parle alors
de classe-association.
Commentaires :
- La présence des "cadenas" provient simplement du logiciel utilisé - Rose de Rational - pour désigner des attributs privés.
- La classe-association ne porte pas de valeurs de multiplicité. Chaque instance de la classe-association Mariage est reliée à un couple d'instances des classes Homme et Femme.
3.a.5 Une classe association peut participer à d'autres relations.
A partir de l'exemple précédent, imaginons que le mariage soit
l'objet d'un contrat de mariage type.
Commentaire : la classe-association Mariage peut participer à des relations propres. Chaque mariage donne lieu ou pas à un contrat type.
3.a.6) Association à arité supérieure à 2.
Reprenons le thème des revues
disponibles dans différents points de vente. Imaginons que nous désirions
suivre les disponibilités hebdomadaires.
Commentaires :
- L'association - ternaire ici - est matérialisée par un losange.
- Une valeur de multiplicité minimum à 0 signifierait, par exemple
pour la revue, qu'une revue n'a été disponible dans aucun point
de vente quelque soit la semaine.
Comme pour toute association, elle peut être porteuse d'attributs. Par
exemple, ici, enregistrons les ventes hebdomadaires de revues par point de vente.
Commentaire : chaque instance de la classe-association Vente, en plus de pointer sur un triplet d'instances des trois classes, contient un attribut.
3.c Agrégation et composition.
Une association relie deux - ou plus - classes, sans induire de rôle particulier pour une classe ; l'association se lie indistinctement dans les deux sens. L'agrégation et la composition vont modéliser une situation où l'une des classe joue un rôle particulier, l'association n'est plus symétrique.
C'est une relation particulière
qui attribue à l'une des classes le rôle d'agrégat et à
l'autre classe le rôle d'agrégé. L'agrégation peut
être assimilée à une appartenance - faible -.
Soit une configuration constituée
d'un certain nombre d'éléments.
Commentaires :
- L'agrégation se modélise
par un losange côté agrégat.
- Une configuration comporte un clavier
-ou aucun -, un écran -ou aucun - , et éventuellement plusieurs
disques.
L'agrégation traduit une
relation d'appartenance de l'agrégé dans l'agrégat ; elle
ne sous-entend aucune valeur de multiplicité particulière :
Commentaires :
- Une page
peut contenir des images mais celles-ci peuvent appartenir à d'autres
pages.
- la destruction
d'une page n'entraîne pas celle de l'image mais seulement la suppression du
lien.
Bien sûr nous aurons très souvent une multiplicité 1..1 ou 0..1 côté agrégat.
L'appartenance est dite faible car l'agrégé pourra participer à d'autres agrégats et son cycle de vie n'est pas subordonné à celui de son agrégat. Dans notre autre exemple, la disparition d'une configuration n'entraîne pas la disparition des périphériques.
Il s'agit d'une appartenance forte.
La vie de l'objet composant est liée a celle de son composé. La
notion de composant est proche de celle d'attribut, si ce n'est que "l'attribut"
est "rehaussé" au rang de classe. On parlera de de réification.
Commentaires :
- La composition
se modélise par un losange noir côté composé.
- Une application
contient de 0 à n fenêtres qui contiennent de 0 à n boutons.
- La fermeture
de l'application entraîne la destruction des fenêtres qui entraîne la
destruction des boutons.
- la non-présence
des valeurs de multiplicités est synonyme de 1..1.
Règles :
- Un composant ne peut appartenir à un moment donné qu'à
un composé.
- La cardinalité ne peut être que de 1 maximum côté composé.
- La suppression du composé entraîne celle du composant.
Exemple récapitulatif
Commentaires :
- Le châssis
est un élément indissociable d'une voiture, d'où la composition.
- On estime
que le moteur
et les roues peuvent être utilisés dans d'autres voitures.
- Les valeurs 4..4 caractérisent plus précisément les valeurs de multiplicité.
- Les absences
de cardinalité sont assimilable à 1..1.
- L'association
entre Voiture et Personne n'est pas nommée, cela est conseillé
lorsque son nom est trivial : "appartient", "concerne"... afin de ne
pas alourdir le modèle, sans rien apporter à la sémantique.
3.d Navigabilité
Dans une association, on peut en général naviguer d'une classe à l'autre. Il est parfois nécessaire à certaines étapes de la conception d'indiquer que la navigabilité n'est plus bidirectionnelle. Le parcours de l'association privilégie un sens particulier de navigation. Par exemple dans une gestion de prêts de livre, on peut concevoir que la bibliothèque connaisse ses livres, mais il ne semble pas nécessaire à chaque livre de connaître la bibliothèque. Nous pouvons interpréter ce choix par une navigabilité restreinte.
Navigabilité restreinte : de la bibliothèque vers les livres.
Remarques :
Cette notion est très importante dans le monde objet. Son implémentation sous forme d'héritage donne tout son sens au concept de réutilisation.
Nous avons mis en oeuvre un premier niveau de classement en regroupant les objets en classes, nous franchissions là un premier niveau d'abstraction. La généralisation nous propose d'en franchir un second niveau.
Le concept de généralisation
est largement utilisé dans le domaine scientifique afin de modéliser
un classement hiérarchique. Classement des espèces chez les biologistes,
classement des végétaux chez les naturalistes, classement des
objets célestes pour les physiciens astronomes.
La spécialisation s'applique
lorsqu'une classe affine les propriétés -attributs et comportements- d'une autre classe. Les termes de généralisation et spécialisation
s'appliquent à un même type de relation entre classes ; on peut
employer l'un ou l'autre selon le sens de lecture.
Exemple
Commentaires :
- Les véhicules à traction humaine et à moteur sont des
sortes de véhicules. Elles en précisent les propriétés
sur certains points, de même pour le vélo qui spécialise
les véhicules à traction humaine ou pour les motos et les voitures.
- Les relations de généralisation sont transitives ; une voiture
est une sorte de véhicule à moteur mais aussi une sorte de véhicule.
- Il n'y a pas de valeur de multiplicité explicite, par principe il s'agit
d'un et un seul dans les deux sens.
- Une moto ne peut être voiture. La contrainte par défaut
est l'exclusion d'objets communs. Nous y reviendrons plus loin.
- En remontant la lecture du diagramme, on peut dire que les propriétés
communes des motos et des voitures sont factorisées dans les véhicules
à moteur.
Par un raccourci de langage, certains assimilent généralisation et héritage ; ceci devra être évité car l'héritage est une technique supportée par la plupart des langages objets. L'héritage relève de l'implémentation, la généralisation de l'analyse.
3.d.1 Généralisation multiple.
Une classe
peut spécialiser plusieurs super-classes.
Commentaire : la classe Ouvrier agricole spécialise les deux classes Ouvrier et Agriculteur, ce qui lui permet de bénéficier des conventions collectives des classes.
La notion de généralisation
multiple est à utiliser avec précaution ; certains langages n'offrent
pas ce concept - Java, Ada -.
Une classe abstraite est une classe qui ne peut être instanciée. Une classe abstraite est utilisée dans deux situations particulières :
+ Les sous-classes forment une couverture de la classe abstraite
Commentaires :
- les personnels
d'un lycée sont soit des enseignants soit des administratifs soit des personnels de
service.
- Les trois
sous-classes "couvrent" l'ensemble des personnels.
+ La classe abstraite ne contient pas suffisamment d'informations pour instancier
un objet, autrement dit cette classe n'est présente que pour factoriser
des propriétés. Il s'agit souvent de classes qui modélisent
un concept.
Commentaires :
- La classe
Courbe modélise plutôt un concept.
- Il existe
d'autres courbes que les paraboles et hyperboles.
Une classe abstraite ne peut pas
se trouver à la fin d'une hiérarchie de classe. Une classe abstraite
doit avoir au moins une sous-classe.
3.d.3 Quelques écueils à éviter
La généralisation est un élément décisif du monde objet. Son utilisation sans règle n'est pas sans risque, nous pointons ici quelques erreurs dues à une généralisation non maîtrisée.
- Hétérogénéité des sous-classes de même niveau
Le critère de construction des deux classes spécialisées Salarié et Libéral est la profession, par contre la classe Sportif relève d'une toute autre classification. Le comportement spécialisé du salarié ou du libéral ne pourrait bénéficier au sportif. Il est préférable de faire :
- Confusion de niveau d'abstraction
Ici, la classe spécialisée ne relève pas du même
niveau d'abstraction ; le modèle de voiture rend compte d'un concept,
la voiture d'une identité physique. La spécialisation ne
convient pas; celle-ci ne doit pas être justifiée uniquement par
la factorisation de propriétés -c'est le cas ici- mais elle
doit aussi relever d'un même niveau d'abstraction. La classe Modèle
de voiture peut être vue comme une "méta-classe" - type de
voiture- alors que la classe Voiture doit être perçue comme une classe
"physique".
La théorie des ensembles fournit un substrat à la notion de généralisation.
Dans cette hypothèse, une classe spécialisée représente
un sous ensemble -par valeur- de la sur-classe ; ce n'est pas le cas dans
cet exemple, il y a beaucoup plus de voitures que de modèles de voiture.
Le modèle conforme serait :
- Non-respect du principe de substitution
Le principe de substitution a été énoncé en 1987 par B. Liskow : " Toute instance d'une sous-classe peut être remplacée par une instance d'une sur-classe sans modification de sémantique ". Autrement dit, si la classe B spécialise une classe A, un objet b de B doit trouver un intérêt dans toutes les opérations de A.
Imaginons que nous disposions d'une classe Liste qui fournissent les opérations suivantes :
Si nous devons implémenter une pile, il serait tentant de faire :
Mais dans cette hypothèse la pile est dénaturée puisqu'elle
va bénéficier d'opérations qui ne concernent pas une telle
structure de données. Il est préférable de faire :
Ainsi, chaque instance de Pile va comporter une instance de Liste, l'utilisateur n'aura accès qu'aux deux opérations Empiler et Dépiler. La pile délègue ses opérations à la liste.
class Pile{ 3.e Classe interface
liste maListe;
public:
...
Empiler(...){
maListe.Dernier();
maListe.Ajouter(...);}
Depiler(){
maListe.Dernier();
maListe.Supprimer();}};
Une classe interface est constituée d'opérations non décrites servant à définir un service particulier d'une classe. Par exemple une classe Personne peut réaliser plusieurs interfaces : un client, un employé, un sportif.
Remarques :
La notion d'interface est très puissante en conception objet, sa mise en oeuvre permet de diminuer le couplage entre les classes en faisant collaborer des classes avec seulement des services nécessaires comme le montre l'exemple suivant :