1.1. Diagramme de classe d’analyse

1.1.1. Diagrammes de classe

Le diagramme de classes est considéré comme le plus important de la modélisation orientée objet, il est le seul obligatoire lors d’une telle modélisation. Alors que le diagramme de cas d’utilisation montre un système du point de vue des acteurs, le diagramme de classes en montre la structure interne. Il permet de fournir une représentation abstraite des objets du système qui vont interagir ensemble pour réaliser les cas d’utilisation. Il est important de noter qu’un même objet peut très bien intervenir dans la réalisation de plusieurs cas d’utilisation.

Les cas d’utilisation ne réalisent donc pas une partition1 des classes du diagramme de classes. Un diagramme de classes n’est donc pas adapté (sauf cas particulier) pour détailler, décomposer, ou illustrer la réalisation d’un cas d’utilisation particulier.

Il s’agit d’une vue statique car on ne tient pas compte du facteur temporel dans le comportement du système. Le diagramme de classes modélise les concepts du domaine d’application ainsi que les concepts internes créés de toutes pièces dans le cadre de l’implémentation d’une application. Chaque langage de Programmation Orienté Objets donne un moyen spécifique d’implémenter le paradigme objet (pointeurs ou pas, héritage multiple ou pas, etc.), mais le diagramme de classes permet de modéliser les classes du système et leurs relations indépendamment d’un langage de programmation particulier.

Les principaux éléments de cette vue statique sont les classes et leurs relations : association, généralisation et plusieurs types de dépendances, telles que la réalisation et l’utilisation.




1.1.2. Les classes
Notions de classe et d’instance de classe


Une instance est une concrétisation d’un concept abstrait. Par exemple :
– la Ferrari Enzo qui se trouve dans votre garage est une instance du concept abstrait Automobile ;
– l’amitié qui lie Jean et Marie est une instance du concept abstrait Amitié ;
Une classe est un concept abstrait représentant des éléments variés comme :
– des éléments concrets (ex : des avions),
– des éléments abstraits ( ex : des commandes),
– des composants d’une application (ex : les boutons des boîtes de dialogue),
– des structures informatiques (ex : des tables de hachage),
– des éléments comportementaux (ex : des tâches), etc.

Tout système orienté objet est organisé autour des classes.
Une classe est la description formelle d’un ensemble d’objets ayant une sémantique et des propriétés communes.

Un objet est une instance d’une classe. C’est une entité discrète dotée d’une identité, d’un état et d’un comportement que l’on peut invoquer. Les objets sont des éléments individuels d’un système en cours
d’exécution.

Par exemple, si l’on considère que Homme (au sens être humain) est un concept abstrait, on peut dire que la personne Marie-Cécile est une instance de Homme. Si Homme était une classe, Marie-Cécile en
serait une instance : un objet.

Notions de propriétés
Une classe définit un jeu d’objets dotés de propriétés. Les propriétés d’un objet permettent de spécifier son état et son comportement. Dans les sections 1.3.2 et 1.3.4, nous avons dit que les propriétés d’un objet
étaient soit des attributs, soit des opérations. Ce n’est pas exact dans un diagramme de classe car les terminaisons d’associations font également partie des propriétés d’un objet au même titre que les attributs et les opérations.

État d’un objet : Ce sont les attributs et les terminaisons d’associations (cf. section 3.3.2) qui décrivent l’état d’un objet. On utilise les attributs pour des valeurs de données pures, dépourvues d’identité, telles que les nombres et les chaînes de caractères. On utilise les associations pour connecter les classes du diagramme de classe. Dans ce cas, la terminaison de l’association (du côté de la classe cible) est une propriété de la classe de base.

Les propriétés décrites par les attributs prennent des valeurs lorsque la classe est instanciée. L’instance d’une association est appelée un lien.

Comportement d’un objet : Les opérations décrivent les éléments individuels d’un comportement que l’on peut invoquer. Ce sont des fonctions qui peuvent prendre des valeurs en entrée et modifier les attributs ou produire des résultats.

Une opération est la spécification (i.e. déclaration) d’une méthode. L’implémentation (i.e. définition) d’une méthode est également appelée méthode. Il y a donc une ambiguïté sur le terme méthode.

Les attributs, les terminaisons d’association et les méthodes constituent donc les propriétés d’une classe (et de ses instances).

Représentation graphique
Une classe est un classeur 2. Elle est représentée par un rectangle divisé en trois à cinq compartiments







Représentation UML d’une classe


Le premier indique le nom de la classe , le deuxième ses attributs et le troisième ses opérations. Un compartiment des responsabilités peut être ajouté pour énumérer l’ensemble de tâches devant être assurées par la classe mais pour lesquelles on ne dispose pas encore assez d’informations. Un compartiment des exceptions peut également être ajouté pour énumérer les situations exceptionnelles devant être gérées par la classe.


Encapsulation, visibilité, interface





Nous avons déjà abordé cette problématique section 1.3.4. L’encapsulation est un mécanisme consistant à rassembler les données et les méthodes au sein d’une structure en cachant l’implémentation de l’objet, c’est-à-dire en empêchant l’accès aux données par un autre moyen que les services proposés. Ces services accessibles (offerts) aux utilisateurs de l’objet définissent ce que l’on appel l’interface de l’objet
(sa vue externe).

L’encapsulation permet donc de garantir l’intégrité des données contenues dans l’objet.

L’encapsulation permet de définir des niveaux de visibilité des éléments d’un conteneur. La visibilité déclare la possibilité pour un élément de modélisation de référencer un élément qui se trouve dans un
espace de noms différents de celui de l’élément qui établit la référence.

Elle fait partie de la relation entre un élément et le conteneur qui l’héberge, ce dernier pouvant être un paquetage, une classe ou un autre
espace de noms. Il existe quatre visibilités prédéfinies.

public ou + : tout élément qui peut voir le conteneur peut également voir l’élément indiqué.

protected ou # : seul un élément situé dans le conteneur ou un de ses descendants peut voir l’élément indiqué.

private ou - : seul un élément situé dans le conteneur peut voir l’élément.

package ou _ ou rien : seul un élément déclaré dans le même paquetage peut voir l’élément.

Par ailleur, UML 2.0 donne la possibilité d’utiliser n’importe quel langage de programmation pour la spécification de la visibilité.

Dans une classe, le marqueur de visibilité se situe au niveau de ses propriétés (attributs, terminaisons d’association et opération). Il permet d’indiquer si une autre classe peut accéder à ses propriétés.

Dans un paquetage, le marqueur de visibilité se situe sur des éléments contenus directement dans le paquetage, comme les classes, les paquetages imbriqués, etc. Il indique si un autre paquetage susceptible d’accéder au premier paquetage peut voir les éléments.

Dans la pratique, lorsque des attributs doivent être accessibles de l’extérieur, il est préférable que cet accès ne soit pas direct mais se fasse par l’intermédiaire de méthodes


Nom d’une classe

Le nom de la classe doit évoquer le concept décrit par la classe. Il commence par une majuscule. On peut ajouter des informations subsidiaires comme le nom de l’auteur de la modélisation, la date, etc.

Pour indiquer qu’une classe est abstraite, il faut ajouter le mot-clef abstract.
La syntaxe de base de la déclaration d’un nom d’une classe est la suivante :
[ ::...:: ]
[ { [abstract], [], [], ... } ]

Les attributs

Les attributs définissent des informations qu’une classe ou un objet doivent connaître. Ils représentent les données encapsulées dans les objets de cette classe.

Chacune de ces informations est définie par un nom, un type de données, une visibilité et peut être initialisé. Le nom de l’attribut doit être unique dans la classe. La syntaxe de la déclaration d’un attribut est la suivante :

[/] :
[ ’[’ ’]’ [ ’{’ ’}’ ] ] [ = ]

Le type de l’attribut () peut être un nom de classe, un nom d’interface ou un type de donné prédéfini. La multiplicité () d’un attribut précise le nombre de valeurs que l’attribut peut contenir. Lorsqu’un multiplicité supérieure à 1 est précisée, il est possible d’ajouter une contrainte () pour préciser si les valeurs sont ordonnées ({ordered}) ou pas ({list}).

Attributs de classe

Par défaut, chaque instance d’une classe possède sa propre copie des attributs de la classe. Les valeurs des attributs peuvent donc différer d’un objet à un autre.

Cependant, il est parfois nécessaire de définir un attribut de classe (static en Java ou en C++) qui garde une valeur unique et partagée par toutes les instances de la classe. Les instances ont accès à cet attribut mais n’en possèdent pas une copie.

Un attribut de classe n’est donc pas une propriété d’une instance mais une propriété de la classe et l’accès à cet attribut ne nécessite pas l’existence d’une instance.

Graphiquement, un attribut de classe est souligné.

Attributs dérivés

Les attributs dérivés peuvent être calculés à partir d’autres attributs et de formules de calcul. Lors de la conception, un attribut dérivé peut être utilisé comme marqueur jusqu’à ce que vous puissiez déterminer les règles à lui appliquer.

Les attributs dérivés sont symbolisés par l’ajout d’un « / » devant leur nom.
Les méthodes


Dans une classe, une opération (même nom et même types de paramètres) doit être unique. Quand le nom d’une opération apparaît plusieurs fois avec des paramètres différents, on dit que l’opération est
surchargée. En revanche, il est impossible que deux opérations ne se distinguent que par leur valeur retournée.

La déclaration d’un opération contient les types des paramètres et le type de la valeur de retour, sa syntaxe est la suivante :

( [ [, [, ...] ] ] ) :
[] [ { } ]

La syntaxe de définition d’un paramètre () est la suivante :
[] : [’[’’]’] [=]

La direction peut prendre l’une des valeurs suivante :

in : Paramètre d’entrée passé par valeur. Les modifications du paramètre ne sont pas disponibles pour l’appelant. C’est le comportement par défaut.

out : Paramètre de sortie uniquement. Il n’y a pas de valeur d’entrée et la valeur finale est disponible pour l’appelant.

inout : Paramètre d’entrée/sortie. La valeur finale est disponible pour l’appelant.

Le type du paramètre () peut être un nom de classe, un nom d’interface ou un type de donné prédéfini.

Les propriétés () correspondent à des contraintes ou à des informations complémentaires comme les exceptions, les préconditions, les postconditions ou encore l’indication qu’une méthode
est abstraite (mot-clef abstract), etc.



Méthode de classe

Comme pour les attributs de classe, il est possible de déclarer des méthodes de classe. Une méthode de classe ne peut manipuler que des attributs de classe et ses propres paramètres.

Cette méthode n’a pas accès aux attributs de la classe (i.e. des instances de la classe). L’accès à une méthode de classe ne nécessite
pas l’existence d’une instance de cette classe.


Graphiquement, une méthode de classe est soulignée.

Méthodes et classes abstraites

Une méthode est dite abstraite lorsqu’on connaît son entête mais pas la manière dont elle peut être réalisée (i.e. on connaît sa déclaration mais pas sa définition).

Une classe est dite abstraite lorsqu’elle définit au moins une méthode abstraite ou lorsqu’une classe parent (cf. section 3.3.1) contient une méthode abstraite non encore réalisée.

On ne peut instancier une classe abstraite : elle est vouée à se spécialiser. Une classe abstraite peut très bien contenir des méthodes concrètes.

Une classe abstraite pure ne comporte que des méthodes abstraites. En programmation orientée objet, une telle classe est appelée une interface.

Classe active

Une classe est passive par défaut, elle sauvegarde les données et offre des services aux autres. Une classe active initie et contrôle le flux d’activités.

Graphiquement, une classe active est représentée comme une classe standard dont les lignes verticales du cadre, sur les côtés droit et gauche, sont doublées.
Relations entre classes

Généralisation et Héritage











La généralisation décrit une relation entre une classe générale (classe de base ou classe parent) et une classe spécialisée (sous-classe).

La classe spécialisée est intégralement cohérente avec la classe de
base, mais comporte des informations supplémentaires (attributs, opérations, associations). Un objet de la classe spécialisée peut être utilisé partout où un objet de la classe de base est autorisé.

Dans le langage UML, ainsi que dans la plupart des langages objet, cette relation de généralisation se traduit par le concept d’héritage. On parle également de relation d’héritage.

Ainsi, l’héritage permet
la classification des objets
Le symbole utilisé pour la relation d’héritage ou de généralisation est une flèche avec un trait plein dont la pointe est un triangle fermé désignant le cas le plus général

Les propriétés principales de l’héritage sont :
– La classe enfant possède toutes les propriétés des ses classes parents, mais elle ne peut accéder aux propriétés privées de celle-ci.


– Une classe enfant peut redéfinir (même signature) une ou plusieurs méthodes de la classe parent. Sauf indication contraire, un objet utilise les opérations les plus spécialisées dans la hiérarchie des
classes.

– Toutes les associations de la classe parent s’appliquent aux classes dérivées.

– Une instance d’une classe peut être utilisée partout où une instance de sa classe parent est attendue.

Par exemple, en se basant sur le diagramme de la figure 3.3, toute opération acceptant un objet d’une classe Animal doit accepter un objet de la classe Chat.

– Une classe peut avoir plusieurs parents, on parle alors d’héritage multiple. Le langage C++ est un des langages objet permettant son implémentation effective, le langage java ne le permet pas.
En UML, la relation d’héritage n’est pas propre aux classes. Elle s’applique à d’autres éléments du langage comme les paquetages, les acteurs ou les cas d’utilisation


Association

Une association est une relation entre deux classes (association binaire) ou plus (association n-aire), qui décrit les connexions structurelle entre leurs instances.

Terminaison d’association vs. Attribut

Un attribut est une association dégénérée dans laquelle une terminaison d’association3 est détenue par un classeur (généralement une classe). Le classeur détenant cette terminaison d’association devrait théoriquement se trouver à l’autre terminaison, non modélisée, de l’association. Un attribut n’est donc rien d’autre qu’une terminaison d’un cas particulier d’association.

Les terminaisons d’associations et les attributs sont donc deux éléments conceptuellement très proches que l’on regroupe sous le terme de propriété structurelle.
Une propriété structurelle peut être paramétrée par les éléments suivant :
nom : Comme un attribut, une terminaison d’association peut être nommée. Le nom est situé à proximité de la terminaison, mais contrairement à un attribut, ce nom est facultatif. Le nom d’une terminaison d’association est appelée nom du rôle. Une association peut donc posséder autant de noms de rôle que de terminaisons (deux pour une association binaire et n pour une association n-aire).

visibilité : Comme un attribut, une terminaison d’association possède une visibilité (cf. section 3.2.4). La visibilité est mentionnée à proximité de la terminaison, et plus précisément, le cas échéant, devant
le nom de la terminaison.

Multiplicité : Comme un attribut, une terminaison d’association peut posséder une multiplicité. Elle est mentionnée à proximité de la terminaison. Il n’est pas impératif de la préciser, mais, contrairement
à un attribut dont la multiplicité par défaut est 1, la multiplicité par défaut d’une terminaison
d’association est non spécifiée. L’interprétation de la multiplicité pour une terminaison d’association
est moins évidente que pour un attribut.
navigabilité : Pour un attribut, la navigabilité est implicite, navigable, et toujours depuis la classe vers
l’attribut. Pour une terminaison d’association, la navigabilité peut être précisée

Association binaire





Une association binaire est matérialisée par un trait plein entre les classes associées.
Elle peut être ornée d’un nom, avec éventuellement une précision du sens de lecture (I ou J).
Quand les deux extrémités de l’association pointent vers la même classe, l’association est dite réflexive.
Association n-aire








Une association n-aire lie plus de deux classes. La ligne pointillée d’une classe-association peut
être reliée au losange par une ligne discontinue pour représenter une association n-aire dotée d’attributs, d’opérations ou d’associations.
On représente une association n-aire par un grand losange avec un chemin partant vers chaque classe participante. Le nom de l’association, le cas échéant, apparaît à proximité du losange.
Multiplicité ou cardinalité
La multiplicité associée à une terminaison d’association, d’agrégation ou de composition déclare
le nombre d’objets susceptibles d’occuper la position définie par la terminaison d’association. Voici
quelques exemples de multiplicité :

– exactement un : 1 ou 1..1
– plusieurs : _ ou 0.._ – au moins un : 1.._ – de un à six : 1..6

Dans une association binaire, la multiplicité sur la terminaison cible contraint le nombre
d’objets de la classe cible pouvant être associés à un seul objet donné de la classe source (la classe de l’autre terminaison de l’association).
Dans une association n-aire, la multiplicité apparaissant sur le lien de chaque classe s’applique sur
une instance de chacune des classes, à l’exclusion de la classe-association et de la classe considérée. Par exemple, si on prend une association ternaire entre les classes (A, B, C), la multiplicité de la terminaison C indique le nombre d’objets C qui peuvent apparaître dans l’association (définie section 3.3.6) avec une paire particulière d’objets A et B.
Remarque
Il faut noter que, pour les habitués du modèle entité/relation, les multiplicités sont en UML « à
l’envers » (par référence à Merise) pour les associations binaires et « à l’endroit » pour les n-aires avec
n > 2.
Navigabilité
La navigabilité indique s’il est possible de traverser une association. On représente graphiquement la navigabilité par une flèche du côté de la terminaison navigable et on empêche la navigabilité par une croix du côté de la terminaison non navigable. Par défaut, une association est navigable dans les deux sens.

Par exemple, sur la suivante, la terminaison du côté de la classe Commande n’est pas navigable :
cela signifie que les instances de la classe Produit ne stockent pas de liste d’objets du type Commande.








Inversement, la terminaison du côté de la classe Produit est navigable : chaque objet commande contient une liste de produits.






Lorsque l’on représente la navigabilité uniquement sur l’une des extrémités d’une association, il
faut remarquer que, implicitement, les trois associations représentées sur la précédente ont la même
signification : l’association ne peut être traversée que dans un sens.








Nous avons dit précédemment que :
« Un attribut est une association dégénérée dans laquelle une terminaison d’association est détenue par un classeur (généralement une classe). Le classeur détenant cette terminaison d’association devrait théoriquement se trouver à l’autre terminaison, non modélisée, de l’association. Un attribut n’est donc rien d’autre qu’une terminaison d’un cas particulier d’association. »

La figure précédente illustre parfaitement cette situation. Attention toutefois, si vous avez une classe Point dans votre diagramme de classe, il est extrêmement maladroit de représenter des classes (comme la classe Polygone) avec un ou plusieurs attributs de type Point. Il faut, dans ce cas, matérialiser cette propriété de la classe en question par une ou plusieurs associations avec la classe Point.

Commentaires

Posts les plus consultés de ce blog

Diagrammes de conception