• Aucun résultat trouvé

Support de formation Modélisation orientée objets UML perfectionnement

N/A
N/A
Protected

Academic year: 2021

Partager "Support de formation Modélisation orientée objets UML perfectionnement"

Copied!
75
0
0

Texte intégral

(1)

Support de Cours

Jean-Michel DISCHLER

Modélisation orientée objets

UML

IUP 2

ème

année

(2)

Table des matières

Introduction à l’approche objet

Les éléments de base de l’approche objet

Conception avec UML, principes

Un aperçu des diagrammes UML

Acteurs et diagramme de cas d’utilisation

La base de données : le diagramme des classes

Les diagrammes de séquence

Les diagrammes de collaboration

Les diagrammes d’objets

Les diagrammes d’état

Les diagrammes d’activités

Le diagramme de déploiement et de composants

Un exemple de spécification UML

(3)

Introduction

Analyse, Conception et Programmation orientée objets

La création d’un système informatique (logiciel, progiciel, système d’information, etc.) révèle toujours deux aspects fondamentaux qui sont : (1) l’analyse et la conception d’une part, et (2) la programmation d’autre part. Schématiquement la conception d’un système se présente comme suit :

Méthode d'analyse langage de prog.

Problème ---> Concept formel ---> Programme

(ce que l'on veut) (solution) (réalisation)

Ces deux aspects sont évidemment directement couplés : l’aspect programmation découle directement de l’analyse. Cette dernière tente de se détacher des aspects “techniques” de la programmation. Elle apporte la solution et spécification formelle à un problème. La programmation en fait la réalisation “physique”.

1.

Aspect : analyse et conception

La phase dite d'analyse et conception représente la phase la plus importante pour aller du problème vers sa réalisation. Cette phase correspond à la question "comment?".

Il faut une méthodologie et démarche rigoureuse pour répondre à ce problème. La

rigueur induit le choix d'un formalisme clair qui ne doit pas prêter à confusion. Il est

évident que la langue française et sa richesse ne permettent pas un tel formalisme :

souvent les mots et phrases du français courant sont ambiguës. En général, le système

n’est seulement décrit qu’initialement à travers un cahier des charges en français, ce

cahier des charges dépeignant de manière purement informelle les besoins. L’analyse permet ensuite de traduire ces besoins en une spécification formelle d’un système informatique.

La grande complexité des systèmes fait que, souvent, ceux-ci sont décomposés de manière hiérarchique en sous-systèmes plus petits, qui sont eux-même décomposés en sous-sous-systèmes encore plus petits, etc., jusqu’à arriver à des systèmes “élémentaires” qu’il n’est plus nécessaire de décomposer (il s’agit d’une arborescence de systèmes obtenus par méthode descendante ou ascendante).

Il est clair que la structure et les liens entre ces sous-systèmes vont influer grandement

sur la qualité du système global, sachant que les critères de qualité d’un système ou

logiciel informatique se déclinent généralement de la manière suivante :

Capacité fonctionnelle : elle caractérise la capacité d’un système informatique

à répondre aux besoins exprimés ;

Fiabilité : elle porte sur l’aptitude du système à maintenir son niveau de

service dans des conditions précises et pendant une période déterminée ;

Facilité d’utilisation : cet élément porte sur l’effort qu’il est nécessaire de

(4)

Rendement : cet élément porte sur le rapport existant entre le niveau de service

d’un système et la quantité de ressources employées pour le faire fonctionner ;

Maintenabilité : cet élément porte sur l’effort nécessaire pour faire des

modifications données.

Portabilité : cet élément concerne l’aptitude du système à être transféré d’un

environnement à un autre ;

Qualité ergonomique : cet élément peut être évalué de diverses façons, selon

des critères psychologiques par exemple. En général, l’interface homme-machine (IHM) doit être cohérente et homogène en présentation et en interaction.

De façon générale, un “bon” système résulte de l’évolution d’un système plus simple vérifiant déjà l’ensemble de ces critères.

2. Aspect : programmation

Cette phase est souvent bien plus élémentaire et triviale. Il s’agit d’un aspect purement technique. Dans de nombreux cas, elle peut être en partie automatisée. Les outils de développement professionnels (issu des ateliers du génie logiciel) qui existent à ce jour, par exemple WinDev, Rational Rose, Objecteering, etc., permettent déjà de générer du

code automatiquement (cf. génie logiciel).

2.1 Approche procédurale classique

En programmation classique (procédurale), un programme se compose de deux

éléments fondamentaux : l’algorithmique (ils s’agit des traitements) et les structures

de données (il s’agit de l’information à traiter).

Le problème d’une telle approche réside principalement dans l’utilisation non structurée des données. En cas d’évolution du système et en particulier des données sous-jacentes,

il faut rechercher, afin de les mettre à jour, tous les traitements ayant trait aux données

concernées. L’exemple 1 qui suit illustre le problème.

Exemple 1. Calculer l’aire d’un triangle défini par trois points de l’espace 2D

Version 1 : utilisation de variables explicites pour les

coordonnées (structure de donnée inexistante)

Programme aire

Avec Ax, Ay, Bx, By, Cx, Cy : réels Début

Saisir Ax, Ay, Bx, By, Cx, Cy

Afficher “l’aire vaut : ”, 0.5*((Bx-Ax)*(Cy-Ay)-(Cx-Ax)*(By-Ay))

(5)

Version 2 : utilisation de tableaux pour les coordonnées Programme aire

Avec A[2], B[2], C[2] : réels Début

Saisir A[1], A[2], B[1], B[2], C[1], C[2]

Afficher “l’aire vaut : ”, 0.5*((B[1]-A[1])*(C[2]-A[2])-(C[1]-A[1])*(B[2]-A[2]))

fin

Version 3 : utilisation d’une structure de type couple pour les

coordonnées

Programme aire

Avec type couple = { x, y : réel } A, B, C : couple

Début

Saisir A.x, A.y, B.x, B .y, C.x, C.y

Afficher “l’aire vaut : ”, 0.5*((B.x-A.x)*(C.y-A.y)-(C.x-A.x)*(B.y-A.y))

fin

Le choix de la structure de données influe tout naturellement sur les traitements. Une modification de ce dernier induit logiquement une modification de tous les traitements lui ayant trait. Dans le cadre de grands systèmes informatiques, le nombre de traitements pour un choix de structure de données précis peut très vite devenir très important. Si bien que les critères de maintenance et de portabilité deviennent également très vite extrêmement déficients.

Par ailleurs, ce type d’approche engendre souvent des liens très forts entre les différents sous-systèmes le constituant. La modification d’un sous-système (ensemble de procédures et fonctions) engendre par-là, la nécessité de modifier un autre sous-système fortement connecté à ce dernier et ainsi de suite. L’effet boule de neige conduit à des systèmes qui dans leur ensemble sont difficiles à faire évoluer facilement et de manière très localisée.

Les deux problèmes précédents ont donc tout naturellement conduit les informaticiens à investiguer des alternatives plus efficaces et répondant mieux aux besoins évolutifs d’un système. Il s’agit de l’approche objet.

2.2 Approche objet

Avec une approche de type objet, un programme est essentiellement composé d’un ensemble d’objets communiquant entre eux. Les objets sont eux-mêmes composés de

deux éléments : les données (partie statique de l’information) et les méthodes (partie

dynamique de l’information). Contrairement à une approche procédurale, l’accent n’est plus mis sur le choix de la modélisation des données mais sur leur comportement. Un objet représente donc une forme d’abstraction de l’information à traiter.

L’exemple 1 du problème précédent (calcul de l’aire d’un triangle) s’écrit au travers d’une vision objet de la manière suivante :

(6)

Exemple 1 – revu en version objet avec deux classes : point2D et vecteur2D Programme aire Avec A, B,C : point2D V1,V2 : vecteur2D Début Saisir A,B,C V1 := vecteur2D(A,B) V2 := vecteur2D(A,C)

Afficher “l’aire vaut : ”, 0.5*V1.Determinant2D(V2) fin

L’exemple montre clairement que l’accent n’est plus mis sur la structure de données (ici, elle n’est pas même connue, d’ailleurs, elle n’a aucun lieu de l’être), mais sur les traitements qu’il est possible d’effectuer, en l’occurrence : 1. saisir un point, 2. initialiser un vecteur à partir de deux points, 3. récupérer le déterminant entre deux vecteurs.

Les deux objets utilisés précédemment co-opèrent entre eux pour résoudre un problème général. Il aurait évidemment été possible d’utiliser directement un objet triangle, auquel cas le programme aurait été le suivant :

Exemple 1 – revu en version objet avec une classe triangle

Programme aire

Avec tri : Triangle Début

Saisir tri

Afficher “l’aire vaut : ”, tri.Aire() fin

De façon générale, la structure de donnée utilisée devient secondaire et reste

complètement cachée à ce que l’on appelle communément le client (ou l’utilisateur) de

l’objet. Un objet n’est vu qu’à travers ses méthodes (celles-ci sont des sortes de

fonctions et procédures, mais attention : il s’agit d’une chose très différente !). Une méthode est un service. Elle se rapporte toujours à la forme abstraite de l’objet qui est la

classe – en fait, elle en fait partie intégrante, c’est ce qui explique l’écriture suivante :

tri.Aire(). Ici, tri est une instance de la classe Triangle. Ce que l’on veut c’est appliquer la méthode Aire (qui calcule donc la superficie) définie au sein de la classe Triangle, à un objet bien particulier : tri. Ceci ce fait au travers d’un mécanisme complexe qui peut être traduit par le biais de messages. Si un service “Aire” existe et est accessible pour l’objet particulier tri, alors cette demande sera honorée et un résultat fourni en retour. De manière un peu plus concrète, tri.Aire() doit être lu et compris comme : essayer d’appliquer la méthode (ou le service) Aire à l’objet particulier tri qui est une instance de la classe Triangle.

(7)

Evidemment deux cas de figure peuvent se présenter :

La méthode requise existe et est accessible à l’objet en question, auquel cas elle fournit un résultat correspondant à sa spécification.

La méthode n’existe pas ou n’est pas accessible à cet objet, auquel cas une exception est générée. Le résultat dépend alors de l’application et du traitement qu’a prévu le concepteur du système.

2.3 Les trois niveaux dans le modèle objet

Programmation orientée objets (POO) : il s’agit de la mise en œuvre physique

d’un modèle conceptuel objet. Elle fait intervenir des ensembles d’objets co-opérants entre eux pour résoudre physiquement le problème décrit dans le cahier

des charges. Chaque objet représente une instance de classe, les classes étant

elles-mêmes membres d’une hiérarchie unifiée par les relations d’héritage.

Concrètement : ce sont les langages de POO tels que Java, C++ ou Smalltalk, qui permettent d’effectuer la programmation

Conception orientée objet (COO) : il s’agit d’un processus de conception

incorporant le processus de décomposition orientée objets et une notation permettant de dépeindre à la fois les modèles logiques, physiques, statiques et

dynamiques du système à concevoir.

Concrètement : il s’agit de se donner un formalisme d’écriture (un langage, par exemple graphique) permettant de comprendre de manière formelle le système.

Analyse orientée objets (AOO) : il s’agit de l’examen des besoins pour

déterminer d’après le vocabulaire du domaine du problème (du cahier des charges) les classes et objets nécessaires à la conception du système. Concrètement : il s’agit de réfléchir à la nature des classes et des objets dont le système va avoir besoin.

(8)

Eléments fondamentaux de l’approche

objet

1. Abstraction et classe

Une abstraction peut être vue comme une description simplifiée d’un système mettant l’accent sur certains détails ou propriétés de celui-ci. Une bonne abstraction met l’accent sur les éléments réellement les plus significatifs en supprimant temporairement les éléments secondaires.

Une abstraction doit faire ressortir les caractéristiques essentielles d’un objet réel, en d’autres termes les caractéristiques qui permettent de le distinguer de tous les autres objets. Ceci permet de procurer des frontières conceptuelles bien définies.

Dans l’approche objet, une classe est un modèle pour plusieurs objets à particularités similaires. Les classes réunissent donc toutes les caractéristiques d’un ensemble d’objets. Une classe “arbre” peut décrire toutes les caractéristiques d’un arbre : feuilles,

racines, branches, etc. Une instance de classe est un objet réel, alors que la classe reste

une représentation abstraite.

arbre sapin Hetre

L’abstraction d’un système doit permettre de faire ressortir les éléments les plus pertinents. Par exemple dans un système de contrôle de flux frontalier, une abstraction pertinente décrit le comportement des individus traversant la frontière : origine, type de motorisation, fréquence de passage et non des détails complètement inutiles à ce système comme le nom ou la couleur de cheveux des conducteurs.

Communément, on distingue les trois genres d’abstractions (il s’agit d’une liste non exhaustive) :

Abstraction d’entité : représente un modèle d’une entité du monde du

problème ou de la solution ;

Abstraction d’action : procure un ensemble généralisé d’opérations réalisant

toutes le même genre de fonctions (affichage, saisie, etc.) ;

Abstraction de coïncidence : regroupe un certain nombre d’opérations qui

(9)

2. Encapsulation

L’encapsulation est la mise en œuvre de l’abstraction. Le principe d’encapsulation consiste à cacher à l’utilisateur d’un objet certains détails de ce dernier. La structure interne de l’objet (les champs et leur valeur) ainsi que le codage des méthodes (type d’algorithme utilisé, etc.) n’a et ne doit avoir aucun intérêt pour l’utilisateur de l’objet, sauf dans des cas très particuliers. Le mécanisme est mis en œuvre de manière pratique par l’interdiction formelle d’accéder à des informations lorsque celles-ci sont déclarées

privées. Inversement les informations ne sont qu’accessibles dans le cas d’une

déclaration publique.

Il est fondamental que le concepteur et développeur du système fasse la séparation entre la spécification de l’objet (profile des méthodes permettant d’utiliser l’objet) et son implantation physique (données + algorithmes).

Dans l’exemple de l’aire du triangle du chapitre précédent, la conception interne de l’objet tri n’a pas à intéresser l’utilisateur de cet objet. Par contre, il est nécessaire qu’il connaisse l’ensemble des “services” accessibles et la manière dont il peut y accéder. Ceci se fait par le biais du profil des méthodes. Ces méthodes ont quant à elles évidemment le droit d’accéder à toutes les informations privées pour pouvoir réaliser la spécification.

3. Hiérarchisation et héritage

Lorsque l’on travaille avec des ensembles de classes plus ou moins complexes, on est très vite amener à créer des hiérarchisations sémantiques. Deux cas peuvent se produire :

Soit une classe est spécialisée : par exemple une classe véhicule se spécialise en

voiture, camion, moto, etc.

Soit plusieurs classes ayant trait à une même catégorie sont regroupées dans une classe plus générale comme les classes : sapin, épicéa, cèdre, etc. en une classe

conifères, elle-même pouvant être généralisée en une classe arbre etc.

Ces généralisations et spécialisations se font lors de la phase d’analyse et conception du système. Elles permettent de construire une description hiérarchisée de classes unifiées

par la notion d’héritage. Cela signifie qu’une classe peut hériter des propriétés de sa

classe mère (aussi appelée super-classe), comme les données, les méthodes, etc.

Celles-ci peuvent alors être modifiées (surcharge, filtrage, restriction, etc.) ou de nouvelles ajoutées pour préciser une spécificité de comportement. Ce mécanisme permet entre autres, de forcer une structuration plus méthodique, tout en évitant des redondances inutiles de code. La relation classe et sous-classe est souvent aussi appelée une relation de dérivation. On dit que la sous-classe dérive de sa super-classe.

Dans certains langages, comme Java ou Smalltalk toutes les classes dérivent d’une super-classe qui se trouve toujours tout au sommet de la hiérarchie. Notons que dans la hiérarchie de classes, plus on avance vers le sommet plus les concepts sont abstraits et plus on descend, plus ils sont concrets.

(10)

Remarque : il est important de ne pas confondre dérivation avec composition. En

effet, une classe donnée peut se composer d’autres classes sans pour autant en dériver (c’est-à-dire sans qu’il n’y ait aucune relation hiérarchique). Par exemple une voiture dérive d’une classe véhicule. Elle comporte quatre roues, un moteur, etc. Roue et moteur représentent des classes à part entière. Cependant ces classes n’entrent pas dans une relation d’héritage avec voiture, elles la composent simplement.

4. Polymorphisme

Le polymorphisme consiste en la concrétisation de l’abstraction d’action. Un même nom de méthode peut être attribué à des classes différentes qu’elles soient liées par une relation d’héritage ou non.

Dans le cas de classes non liées par héritage, l’intérêt du polymorphisme est essentiellement celui de pouvoir abstraire une méthode. Prenons par exemple deux classes A et B, chacune possédant une méthode d’affichage de même nom affiche(). Il est à présent possible de créer des listes d’éléments d’instances de ces deux classes : une liste comprenant à la fois des objets A et B. Une méthode, permettant l’affichage de la liste, consistera simplement en un appel pour chacun de ses éléments de la méthode affiche(). Comme chaque objet “porte” non seulement ses propres données mais également l’ensemble de ses méthodes, le système pourra sans aucune difficulté retrouver la méthode affiche() correspondant à l’objet en question (soit la méthode affiche pour A soit celle pour B). Le système permet de différencier les méthodes à la fois grâce aux classes auxquelles elles se rapportent et à la fois, au sein d’une même classe, grâce au profil. En effet, le polymorphisme est également valable au sein d’une

même classe : on parle de surcharge au sein d’une même classe. Cependant dans ce

cas, il faut nécessairement que les profils des méthodes soient différents.

Dans le cas de classes liées par relation d’héritage, le polymorphisme permet d’effectuer des spécialisations ou au contraire des restrictions. Si la classe B dérive de A, et que A possède une méthode f(), alors B peut :

soit également posséder sa propre méthode f() (on parle aussi d’une surcharge, mais à travers l’héritage) ; il s’agira d’une spécialisation ou d’une restriction. La méthode f() propre à B peut : soit compléter celle de A en ajoutant du code supplémentaire tout en conservant le code hérité de A, soit au contraire complètement remplacer la méthode de A en proposant un tout nouveau code restreint à B.

soit ne pas posséder de méthode f(), auquel cas celle de A est héritée telle quelle.

Dans tous les cas la méthode f() est accessible à un objet B. Lorsque la méthode f() est appelée par une instance de B, le système regarde donc d’abord s’il existe un f() propre à B, sinon il prendra le f() du niveau supérieur de la hiérarchie, etc. jusqu’à arriver au sommet.

(11)

5. Un niveau d’abstraction supérieur : la généricité, les classes

abstraites et les interfaces

La généricité n’est pas un élément fondamental à l’approche objet, contrairement aux points présentés précédemment. Il s’agit d’un élément complémentaire qui n’existe pas dans tous les langages (il existe en C++, pas en Java). Le principe de la généricité est celui de créer des modèles (ou des patrons) soit de classes soit d’algorithmes. La

généricité permet en l’occurrence de paramétrer des classes ou des algorithmes par un

ou plusieurs types non encore existant (qui seront préciser ultérieurement). Le but ultime c’est bien sûr d’abstraire la conception au plus possible, afin d’éviter la “réécriture” de code similaire.

Une classe générique ne peut pas être utilisée directement puisqu’il faut d’abord l’instancier à des types spécifiques. Le paramétrage peut être de deux catégories : soit par des classes non encore définies, soit par des constantes de types de bases (entiers, réels, booléens, etc.).

Une classe abstraite est aussi une sorte de modèle abstrait, mais contrairement au concept de généricité la classe abstraite n’est pas paramétrable. Une classe abstraite indique la structure interne que peut avoir un objet théorique sans préciser d’implémentation. Elle ne peut donc pas être instanciée, ni utilisée directement, sauf sous la forme d’une extension par héritage ou d’une implémentation concrète par une autre classe. En C++, les classes abstraites sont des classes qui ne possèdent que des méthodes virtuelles (cf. cours de C++). En Java, une distinction est faite entre classe abstraite et interface, sachant que l’interface ouvre la voie à une forme d’héritage multiple dans la mesure où une classe “concrète” (par opposition à abstraite) peut implémener plusieurs interfaces, alors qu’elle ne peut dériver que d’une seule classe abstraite.

Une interface décrit un comportement visible, qu’il s’agisse d’une classe d’un paquetage ou d’un classificateur. Elle ne comprend donc pas d’attributs, mais uniquement une liste de méthodes dont la visibilité est publique.

La classe abstraite et l’interface représentent des éléments qui servent à abstraire le modèle conceptuel du système. Ce sont donc des éléments importants de modélisation objet.

(12)

Conception avec UML, principes

… vers une unification des modèles …

2.

Historiquement

C’est l’expérience qui a permis de faire un tri entre les différents concepts proposés par les méthodes existantes (Booch, OMT, OOSE, etc.). Pour mettre un terme à la prolifération des méthodes, Booch, Jacobson et Rumbaugh s’unissent en se fixant des objectifs communs :

Permettre de faire une représentation globale des systèmes (au-delà du seul logiciel) par l’approche objet ;

Etablir un couplage entre les concepts et les parties exécutables ; Prendre en compte le facteur d’échelle des systèmes complexes ;

Créer un langage simple utilisable à la fois par les hommes et les machines.

Le problème le plus important a été de trouver un système de notation qui convienne à

tous, et c’est ainsi qu’est né UML, le langage universel de modélisation orienté objets (après plusieurs mises à jours de la Unified Method V 0.8, puis V0.9 et V0.91). En 1997, la version 1.0 d’UML est soumise à l’OMG (object management group). La version 1.1 est acceptée deux mois plus tard à l’unanimité et devient ainsi “le standard” de la modélisation et conception objet.

3.

Les principes

Le terme modélisation est souvent utilisé comme un synonyme d’analyse (décomposition en éléments simples et faciles de compréhension), mais il faut savoir que ces termes sont nuancés : la modélisation consiste à décrire la solution du problème, alors que l’analyse le décompose. UML propose un langage de conception, pas une technique d’analyse. UML s’apparente donc plus à un langage, qui, en l’occurrence, est un langage graphique : une conception UML se présente sous la forme d’un ensemble de graphiques.

Le contenu du modèle dépend évidemment du problème. Un modèle se doit de capturer la sémantique sous-jacente d’un problème et contient des informations ultérieurement exploitées pour la réalisation, i.e. la génération de code, etc.

Les utilisateurs observent les modèles à travers des vues graphiques, qui montrent tout ou une partie de ces modèles. UML propose d’observer et de décrire un système à partir de points de vue différents. Chaque vue est représentée par un ou plusieurs diagrammes. On distingue les vues statiques des vues dynamiques.

(13)

Vues statiques :

Diagrammes de classes ; Diagrammes d’objets ;

Diagrammes de cas d’utilisation ; Diagrammes de composants ; Diagrammes de déploiement. Vues dynamiques : Diagrammes de séquences ; Diagrammes de collaborations ; Diagrammes d’états-transitions ; Diagrammes d’activités.

Les diagrammes permettent une compréhension aisée du système, de son contenu, etc. Ils donnent à l’utilisateur un moyen de visualiser et de manipuler les éléments de modélisation.

Les vues peuvent se décomposer en :

Vue logique : qui décrit les aspects statiques et dynamiques d’un système en

terme de classes et d’objets. Elle se concentre sur l’abstraction et l’encapsulation. Elle se rapporte donc aux objets, aux classes, aux collaborations et aux interactions ;

Vue de la réalisation : se rapporte à l’organisation des parties statiques

(exécutables, code source, etc.) dans un environnement de développement. Elle se rapporte aux composants de type fichiers, tables, bibliothèques, etc. et aux sous-systèmes (packages) ;

Vue des processus : cette vue détermine la décomposition en flots d’exécution

(processus, threads, tâches, etc.). Elle se rapporte aux objets actifs et aux interactions ;

Vue de déploiement : décrit les différentes ressources matérielles et

l’implantation logicielle dans ces ressources ; Elle se rapporte donc aux nœuds du matériel et aux instances de composantes ;

Vue des cas d’utilisation : cette vue valide en quelque sorte les autres vues.

Elle permet d’identifier les interfaces critiques et force les concepteurs à ce focaliser sur les problèmes concrets.

(14)

Un aperçu des diagrammes UML

1. Les différents types de diagrammes

UML est un langage graphique. Le système est décrit par un ensemble de diagrammes,

chacun représentant une “vue”, une spécificité, du système, comme par exemple : par

qui et dans quel cas ce système est-il utilisé, quelles sont les classes et objets du système, quels sont les enchaînements de messages entre utilisateurs (acteurs) et objets du système, où est situer le matériel, comment les objets collaborent-ils entre eux pour réaliser une fonctionnalité, etc.

Les diagrammes sont les suivants :

Diagramme des cas d’utilisation : ce diagramme décrit le comportement

général (action et réactions) du système vis à vis des utilisateurs (plutôt acteurs) du

système ; Il s’agit donc de la description des fonctionnalités : dans quel cas ce système est-il utilisé et par qui ?

Diagrammes des séquences

:

ce diagramme décrit les interactions entre les acteurs et les objets d’un point de vue temporel sous la forme d’un scénario, qui constitue une instance particulière du cas d’utilisation ;

Diagrammes de collaboration : ce diagramme décrit les interactions entre groupes spécifiques d’objets par représentation des liens et des envois de messages ;

Diagrammes de classes :décrit la structure des classes : identité, relations entre les classes (héritage et composition), attributs et opérations ;

Diagrammes d’objets : ce diagramme représente simplement une instance de diagramme de classes, donc pour des cas concrets à un instant donné ;

Diagrammes d’états-transition : Ces diagrammes décrivent les aspects et le

séquencement des opérations en relation avec le temps ; Il s’agit de mettre en évidence les événements qui marquent un changement, des états particuliers, etc. On ne s’intéresse cependant qu’au séquencement, pas à ce qu’effectuent les opérations ;

Diagrammes d’activités : Il s’agit de variantes des diagrammes précédents. Ces

diagrammes mettent en évidence les activités et modélisent les comportement internes des méthodes et opérations ;

Diagramme de composants : ce diagramme décrit les choix de composants :

bibliothèques, fichiers, code, …

Diagramme de déploiement : ce diagramme illustre la disposition spatiale et

physique des différents matériels composant le système ;

2. Un exemple simple : résolution d’une équation du second degré

Dans ce qui suit nous allons brièvement voir un exemple de logiciel spécifié à l’aide du langage UML. Il s’agit d’une calculatrice permettant de résoudre des équations du second degré.

(15)

Commençons par voir par qui et dans quel cas ce système est utilisé. En imaginant que le calcul de racine d’un binôme fasse partie d’un système plus large de calcul scientifique, le présent calcul peut être considéré comme un cas d’utilisation :

Voyons à présent plus en détail le cas d’utilisation “calculer racine” et le déroulement d’une séquence d’utilisation : l’utilisateur commence par saisir les données (les coefficients a,b et c du binôme), le système calcule la solution et l’affiche. Graphiquement, cela peut se traduire comme suit :

On peut aussi entrer un peu plus dans les détails et préciser dors et déjà les objets auxquels ce scénario sera confronté, ainsi que les messages (méthodes) qui seront mises en oeuvre. Nous introduisons les objets suivant : l’écran (la fenêtre de l’application) et le binôme : utilisateur : système Saisie de a,b,c calculer Solution(s) saisie de a,b,c : EcranBinome bi :Binome bi :=creation(a,b,c) affichage de a,b,c demande de calcul calculerRacine() affichage solution utilisateur Calculatrice scientifique calculer racine binôme

(16)

Le diagramme précédent nous montre en quelque sorte le scénario qui se déroule entre l’utilisateur et le système. Nous devons à présent préciser un peu plus comment “en interne” les différents objets collaborent pour réaliser le scénario précédent. Nous savons en particulier qu’avant de calculer la solution, nous devons déterminer le discriminant de l’équation. Ceci fait donc apparaître un nouvel objet : discriminant. Selon la valeur du discriminant nous allons être confronté à trois cas de figure : si le discriminant est négatif il n’y a pas de solution, si le discriminant est nul il n’y a qu’une solution et s’il est positif il y a deux solutions. Nous devons aussi considérer le cas dégénéré où le coefficient a est nul (dans ce cas, le binôme est un monôme).

Nous allons traduire sous forme de schéma les collaborations entre tous ces objets :

A travers ce schéma de collaborations, on fait apparaître les classes et les méthodes dont on va avoir besoin. On en déduit un diagramme de classes :

: EcranBinome 1 : eventSaisie() 2 : eventDemanderSol() bi : Binome di : Discriminant 2.1 : creation(a,b,c) 2.2 : bi :=creation(a,b,c,di) : BinomeSolNeant : BinomeUneSolDouble : BinomeDeuxSol 2.3 : calculerRacines() 2.4 : n :=nbRacines() 2.5 *[i:=1..n] r := valRacine(i) 2.5.i afficher() : EcranBinome - x,y,z : GetBox - t1,t2 : TextBox - bq,bc : Button + eventSaisie() + eventDemanderSol() : Binome - a,b,c : réel + création(…) : Binome + calculerRacines() + nbRacines() : entier + valRacine(i : entier) : réel

di : Discriminant - delta : réel + creation(…) : Discriminant + valeur() : réel : BinomeSolNeant + nbRacines() : entier : BinomeUneSolDouble - sol : réel + nbRacines() : entier 2.3.1 : valeur() 1 1 : BinomeDeuxSol - sol1, sol2 : réel + nbRacines() : entier : BinomeDégénéré

(17)

Dans le diagramme de classes précédent, nous avons introduit d’autres objets, composant EcranBinome, comme GetBox, TextBox, ou Button qui sont des objets de l’interface graphique sur lesquels nous ne nous attarderons pas plus, car ce type d’objet dépend généralement du système et du langage (en fait EcranBinome dérive d’un objet de type Fenêtre qui peut dériver lui-même d’un objet général de type Application ou Applet en Java). De même les méthodes eventSaisie() et eventDemanderSol() sont en fait des méthodes dérivées du système évènementiel sous-jacent (Swing dans le cas de Java par exemple). Nous ne préciserons donc pas plus le contenu de la classe EcranBinome qui nécessite, éventuellement, d’être adaptée à la plate-forme utilisée. Lors du lancement du programme, un objet EcranBinome est créé. Celui-ci ouvre une fenêtre dans laquelle se trouve des widgets qui se mettent en attente d’évènements. Nous pouvons à travers un schéma UML préciser les différents états dans lequel notre logiciel va être amené à se trouver :

A présent nous pouvons nous intéresser à la vue logique, qui consiste à regrouper sous forme de paquetages les différents composants de notre système / application. Nous pouvons distinguer le paquetage Ecrans de celui du Binomes. Schématiquement :

D’autres schémas supplémentaires peuvent encore aider à préciser le système, comme par exemple les composants physiques et leur disposition spatiale, les différents enchaînements d’actions, etc. Dans le cas présent de notre problème, qui se trouve être somme toute assez simple, nous arrêtons ici notre analyse et conception objet.

en attente calcul en cours demande de solution ApplicationBinome Ecrans Binomes <<import>> <<import>>

(18)

A ce stade, les diagrammes nous ont servi à comprendre et à spécifier plus formellement le système. Ils vont aussi nous servir à réaliser le logiciel en l’implémentant en Java par exemple. Pour des raisons de simplicité et de clarté, nous n’allons cependant voir dans ce qui suit que l’implémentation du paquetage Binome en Java. Le paquetage Ecrans, définissant la classe EcranBinome, ne consiste essentiellement qu’à utiliser Swing pour créer les boutons et mettre en place les “écouteurs d’évènements”. Toutefois, nous pouvons représenter graphiquement le genre d’interface que nous pouvons nous attendre à voir pour l’application binôme :

Le code (incomplet) correspondant à EcranBinome peut être à peu de choses prêt le

suivant :

import Binomes.Binome ;

public class EcranBinome extends java.applet.Applet {

// données diverses dont les boites a,b et c etc.

public void init() { //créer ici les boutons, le contexte etc. }

public void eventDemanderSol(double a, double b, double c) {

Discriminant di = new Discriminant(a,b,c) ; Binome bi=creation(a,b,c,di) ;

bi.calculerRacines() ; int n=bi.nbRacines() ;

// mettre à jour le texte de la fenêtre p.r. à n

// -1=> dégénérescence,0=> pas de sol, 1=> sol double

for (i=0 ; i<n ; i++) {

double r=valRacine(i) ;

// mettre à jour la boite corresp. dans la fenêtre

} } etc. }

Saisie de coefficients de l’équation ax2+bx+c=0

a : b : c :

Solutions :

(19)

Ce code correspond exactement à ce que nous avions décrit dans le diagramme des collaborations entre les objets.

Traduisons en Java les classes Binome, Discriminant, BinomeSolNeant, BinomeSolDouble, BinomeDeuxSol et BinomeDegenere:

public class Discriminant { private : double delta ;

public Discriminant(double a, double b, double c) { delta = b*b-4.0*a*c ; }

public double valeur() { return delta ; } }

public class Binome { // données

protected : double a,b,c ; protected : Discriminant dis ; // méthodes (virtuelles)

public Binome(double u, double v, double w, Discriminant d) { a=u ; b=v ; c=w ; dis=d ; }

public Binome creation(double u, double v, double w,

Discriminant d) {

double delta=d.valeur() ;

if (a==0.0) return new BinomeDegenere(u,v,w,d) ; } if (delta<0.0) return new BinomeSolNeant(u,v,w,d) ;

else if (delta==0.0) return new BinomeSolDouble(u,v,w,d) ; else return new BinomeDeuxSol(u,v,w,d) ;

}

public void calculerRacines() { // erreur si ici } public int nbRacines() { // erreur si ici }

public double valRacine(int i) { // erreur si ici } }

public class BinomeSolNeant { // méthodes

public BinomeSolNeant(double u, double v, double w, Discriminant d) { super(u,v,w,d) ; }

public void calculerRacines() { return ; } public int nbRacines() { return 0 ; }

public double valRacine(int i) { // erreur si ici } }

public class BinomeSolDouble { // données

private : double sol; // méthodes

public BinomeSolDouble(double u, double v, double w, Discriminant d) { super(u,v,w,d) ; }

public void calculerRacines() { sol=–b/(2.0*a) } public int nbRacines() { return 1 ; }

public double valRacine(int i) { return sol ; } }

(20)

public class BinomeDeuxSol { // données

private : double sol1, sol2; // méthodes

public BinomeDeuxSol (double u, double v, double w, Discriminant d) { super(u,v,w,d) ; }

public void calculerRacines() {

sol1=(–b+Math.sqrt(dis.valeur())/(2.0*a) ; sol2=(–b-Math.sqrt(dis.valeur())/(2.0*a) ; }

public int nbRacines() { return 2 ; }

public double valRacine(int i) { return i==0 ? sol1 :sol2 ; } }

public class BinomeDegenere { // méthodes

public BinomeDegenere(double u, double v, double w, Discriminant d) { super(u,v,w,d) ; }

public void calculerRacines() { // erreur } public int nbRacines() { return -1 ; }

public double valRacine(int i) { // erreur si ici } }

En conclusion, nous avons finalement obtenu un logiciel structuré répondant bien au cahier des charges que nous nous sommes fixé. La conception à travers UML nous a permis d’obtenir une représentation graphique du système, visionné en quelque sorte sous différents angles (différentes vues). De prime abord ce programme semble plus “compliqué” qu’avec une approche classique (par exemple procédurale, non objet). Mais l’avantage majeur et décisif dans notre cas est la structuration précise et fortement modulaire offrant de nombreux avantages dont essentiellement la maintenabilité. En

effet, il est aisé de faire évoluer ce système vers quelque chose de plus général, par exemple en considérant des racines complexes ou des polynômes de degré supérieur. C’est bien là, l’atout majeur de l’approche objet.

(21)

Les éléments graphiques de base d’UML

Le langage UML est un langage graphique. Nous voyons dans ce qui suit, les différentes règles de notation et les symboles graphiques “de base” utilisés par ce langage, ainsi que leur sémantique.

1.

Les éléments d’UML

Il existe quatre types d’éléments dans UML :

• Les éléments structurels : classe, interface, collaboration, cas d’utilisation, classe

active, composant et nœud ;

• Les éléments comportementaux : messages et états ; • Les éléments de regroupement : les paquetages ; • Les éléments d’annotation : commentaires (ou notes).

Ces éléments sont liés par quatre types de relations :

• La relation de dépendance ; • La relation d’association ; • La relation de généralisation ; • La relation de réalisation.

2.

Les éléments structurels

Ces éléments sont représentés par des noms. Ils représentent les parties les plus statiques du système. Il s’agit d’éléments conceptuels ou physiques.

a. La classe

Une classe est représentée par un rectangle contenant le nom, et éventuellement les attributs et les opérations. Une classe implémente une ou plusieurs interfaces.

Fenêtre - o : Origine - t : Taille +Ouvrir() +Fermer()

(22)

Les attributs sont précédés de : - pour indiquer “privé”, + pour “public” et # pour “protégé” . Une classe peut être paramétrée ou de type <<utilitaire>> (cf. diagrammes des classes). On peut également représenter les types de base avec <<type primitif>>.

b. L’interface

Une interface est un ensemble d’opérations définissant la fonction d’un composant ou d’une classe. L’interface décrit le comportement apparent sans préciser l’implantation, c’est-à-dire qu’elle n’offre qu’un profile ou signature de comportement. On représente en UML une interface par un cercle, sous lequel on précise le nom.

Une notation du type :

signifie que la classe maclasse fournit effectivement les services de l’interface interf. Il est également possible de noter une interface sous forme de classe avec le mot réservé <<interface>>.

c. La collaboration

Une collaboration définit une interaction entre divers éléments qui coopèrent pour fournir un comportement global non réalisable par utilisation des éléments de manière indépendante. Une classe peut participer à une ou plusieurs collaborations. Les collaborations sont représentées par des ellipses en pointillés, qui contiennent simplement leur nom.

Correction

Contrôle de qualité interf

(23)

d. Le cas d’utilisation

Il s’agit de la description d’une action exécutée par le système pour produire un résultat donné, enclenché et attendu par un acteur (utilisateur au sens large). Un cas d’utilisation sert à structurer les éléments comportementaux. Il est réalisé au travers d’une collaboration. Le cas d’utilisation est représenté par une ellipse en trait plein, contenant son nom.

e. La classe active

Il s’agit d’une classe qui peut lancer une activité de commande (par exemple parce qu’elle contient des threads). La classe active est représentée comme une classe normale mais avec un trait épais.

f. Le composant

Un composant est une partie physique du système. Il peut s’agir par exemple d’un fichier code source. Un composant se représente graphiquement par un rectangle avec deux onglets.

Passer une commande

EventManager

suspend() flush()

(24)

g. Le nœud

Un nœud est un élément physique qui intervient lors de la phase d’exécution. Il s’agit d’une ressource de calcul avec une capacité de traitement. Un ensemble de composants peut résider sur un nœud mais peut également se déplacer d’un nœud à l’autre. On représente un nœud par un parallélépipède rectangle.

3.

Les éléments comportementaux

Ces éléments représentent la partie dynamique des modèles UML. Ils correspondent aux verbes du modèle et représentent son comportement à travers le temps et l’espace. Sur le plan sémantique, les éléments comportementaux sont habituellement liés à divers éléments structurels comme essentiellement les classes, les collaborations et les objets.

a. Le message

Une interaction est un comportement qui comprend un ensemble de messages échangés au sein d’un groupe d’éléments pour atteindre un but défini. Les messages font partie d’une interaction. Les messages sont représentés par une flèche.

b. L’état

Un automatique à états finis permet de préciser les séquences d’états des éléments au cours de leur durée de vie, en réponse à des évènements. Un état est représenté par un rectangle ayant des angles arrondis. Ce rectangle contient le nom de l’état et les éventuels sous-états.

serveur

afficher

(25)

4.

Les éléments de regroupement

Ces éléments représentent les parties organisationnelles des modèles UML. Ce sont des boites dans lesquels les modèles peuvent être décomposés. Il existe un seul type fondamental d’élément de regroupement : les paquetages. Un paquetage est un mécanisme général qui permet de regrouper des éléments. Il s’agit donc d’un mécanisme purement conceptuel. La représentation graphique est un dossier étiqueté :

5.

Les éléments d’annotation

Ces éléments représentent les parties explicatives. Les notes ou commentaires sont utiliser pour clarifier et décorer les diagrammes. On les représente graphiquement comme suit :

6.

Les relations de base dans UML

6.1 La dépendance

Une dépendance est une relation sémantique entre deux éléments, telle que le changement apporté à l’un des éléments (élément indépendant) affecte le second (élément dépendant). La relation de dépendance est représentée par une flèche en pointillés. Elle peut contenir une étiquette, comme par exemple <<utilise>>.

Règles métier

(26)

6.2 L’association

L’association est une relation structurelle. L’agrégation et l’assemblage par exemple représentent des relations d’association. Celle-ci est représentée par une ligne munie des multiplicités et des rôles respectifs des deux éléments associés :

6.3 La généralisation

Il s’agit d’une relation hiérarchique selon laquelle le parent représente une généralisation de l’enfant, et inversement l’enfant une spécialisation du parent. Cette relation se représente par une flèche dont la pointe est dirigée vers le parent.

6.4 La réalisation

Une réalisation est une relation sémantique entre classificateurs. Un classificateur propose un contrat dont l’autre classificateur en garantit la réalisation. Ce type de relation apparaît dans deux cas de figure : entre les interfaces et les classes qui les réalisent et entre les cas d’utilisation et les collaborations qui les réalisent également. La représentation graphique est une flèche avec un trait en pointillé.

0..1 *

(27)

Diagramme des Cas d’Utilisation

Spécifier l’interaction du système avec les acteurs

Il s’agit souvent du point de départ d’une conception objet. Les diagrammes de cas d’utilisation servent à modéliser les aspects dynamiques d’un système. Ils montrent les divers cas d’utilisation du système par des acteurs et visualisent donc son comportement. Ce type de diagrammes comporte :

• Des cas d’utilisation ; • Des acteurs ;

• Des relations de dépendance, de généralisation et d’association.

Il est utilisé pour modéliser soit le contexte d’un système soit les exigences de ce système.

Pour modéliser le contexte d’un système, il faut :

• identifier les acteurs qui entourent ce système. Certains acteurs utilisent le

système pour accomplir des tâches (acteurs principaux), d’autres effectuent des tâches de maintenance ou d’administration (acteurs secondaires), enfin, d’autres correspondent à des systèmes externes ou du matériel périphérique.

• organiser les acteurs selon une hiérarchie de généralisation / spécialisation ; • intégrer les acteurs au diagramme en spécifiant les cas d’utilisation auxquels ils

se rapportent.

4.

Les acteurs

Un acteur représente un rôle joué par une personne ou une chose en interaction avec le système.

L’acteur peut être représenté de deux manières :

nom

<<acteur>> nom

(28)

Un acteur peut être une spécialisation d’un acteur déjà défini. Dans ce cas, on utilise une relation de généralisation :

5.

Les cas d’utilisation

Un cas d’utilisation représente une fonctionnalité d’un système. Il est lié par association à un ou plusieurs acteurs, ou à d’autre cas d’utilisation par relation de généralisation ou

de dépendance. La dépendance peut être interprétée de deux façons :

• Inclusion : un cas d’utilisation comprend le comportement décrit dans le cas qui

est inclus. Ceci permet de décomposer des comportements ;

• Extension : un cas d’utilisation ajoute son comportement. Ceci permet de

modéliser des variantes de comportement. Exemples :

Il peut également exister une relation d’héritage entre cas d’utilisation. Cette relation exprime une spécialisation (ou inversement une généralisation).

Les questions à se poser pour identifier les cas d’utilisation sont les suivantes :

• Quelles sont les tâches des acteurs ; • Quelles informations doivent être traitées ;

• Quelles actions internes et externes sont susceptibles d’influencer le système.

Acteur spécialisé Acteur général Passer un appel téléphonique

Passer un appel pour conversation à trois <<étend>>

(29)

6.

Diagramme des cas d’utilisation

Le diagramme des cas d’utilisation regroupe dans un même schéma les acteurs et les cas d’utilisation en les reliant par associations et en délimitant le système par un cadre rectangulaire.

Voici un exemple de diagramme de cas d’utilisation pour un système de téléphone portable. On se concentrera sur les acteurs suivants : l’utilisateur et le réseau mobile (“derrière” la boîte noire qu’est le téléphone), sans se préoccuper du prestataire.

7.

Aller vers des objets

Un cas d’utilisation est réalisé par une collaboration entre objets : en d’autres termes c’est en associant une collaboration au cas d’utilisation que l’on accomplit le cas d’utilisation. Un scénario permet de décrire la collaboration en précisant les échanges de messages. Le diagramme correspondant est le diagramme de séquences. Un autre diagramme, appelé diagrammes des collaborations représente une instanciation du cas d’utilisation en décrivant les interactions entre objets participant à la collaboration.

réseau

utilisateur

Téléphone mobile

Passer appel Passer appel

à trois

Recevoir appel Recevoir un nouvel appel

Utiliser agenda

<<étend>>

(30)

Graphiquement la collaboration se représente comme suit :

8.

Un exemple concret : le car-sharing

Cahier des charges (description informelle du système)

Le principe du car-sharing (partage de voiture) est le suivant : un certain nombre de clients se partagent en location un parc automobile. Une entreprise gère cette location et propose à ses clients un ensemble de voitures au choix. Chaque client accède au parc à travers une porte à verrouillage électronique en utilisant son badge. De là, il prend possession d’une voiture qu’il peut utiliser librement pendant une durée indéterminée mais limitée. Lorsqu’il n’a plus besoin du véhicule, il effectue d’abord le plein, puis le ramène au parc. A la fin du mois, les heures d’utilisation sont facturées à chaque client selon la durée d’utilisation de la voiture et sa catégorie (classe A, B ou C), indépendamment du kilométrage effectué.

De manière concrète un nouveau client se présente à un guichet où un employé le prend en charge. Après présentation d’une pièce d’identité, du permis, et d’un chèque de caution, ce nouveau client se voit attribuer par courrier un numéro de client, un code secret et un badge, lui permettant d’effectuer librement une location de véhicule à toute heure du jour ou de la nuit n’importe quel jour de la semaine.

Pour louer un véhicule, le client se rend au parc, auquel il accède grâce à son badge. Dans le parc, il a accès à un clavier d’ordinateur avec écran et souris où un logiciel l’accueille. Ce logiciel lui permet de choisir un véhicule dans une liste de véhicules disponibles. Le client effectue un login grâce à son numéro et son code secret. La liste de véhicules disponibles est affichée. Une fois son choix effectué, le logiciel affiche un numéro de clé et un code d’accès à cette clé. Le client se rend à un boîtier contenant toutes les clés de tous les véhicules. Les clés ne peuvent pas être retirées car elles sont verrouillées électroniquement dans leur serrure. Une borne avec un clavier numérique permet au client de saisir le numéro de clé puis le code d’accès à cette clé. Si le code est bon, la clé en question est déverrouillée et le client peut la retirer. A partir de ce moment un compteur se met en marche dans le système, qui va enregistrer la durée de la location. De même la base de données est mise à jour en retirant le véhicule en question de la liste des véhicules disponibles.

mon cas

d’utilisation ma collaboration

<<réalise>>

Objet A

(31)

Lorsqu’un client ramène une voiture, il place simplement la clé dans la serrure du boîtier où il l’avait retirée au paravent. En tournant la clé dans sa serrure, elle est instantanément verrouillée et ne peut plus être retirée. Le système ajoute automatiquement le véhicule dans la liste des véhicules disponibles et arrête le compteur du client. Un nouveau code d’accès pour la clé restituée est créé, afin d’éviter les fraudes ultérieures (le client connaissant à présent le code de la clé, il pourrait reprendre le même véhicule sans le louer!). Le client ayant rendu son véhicule peut quitter le parc ou choisir de louer une autre voiture.

L’employé sert d’administrateur du système : il peut créer des nouveaux clients, ajouter ou retirer temporairement ou définitivement des véhicules de la base (par exemple pour cause de révision).

Certains traitements particuliers doivent être considérés pour ce système : par exemple, lorsque le client prend un véhicule et constate que son prédécesseur a omis de refaire le plein, ou bien le véhicule ne démarre pas... A ce moment, il n’utilise pas la voiture, mais se re-connecte au système avec son login. Le système “remarque” que ce client vient tout juste de prendre possession d’une voiture et propose un nouveau menu spécifique de “plainte”. Là le client peut “rendre” la voiture sans facturation d’utilisation (à condition évidemment que le délai entre le retrait de la clé et le login est inférieure à une durée limite donnée – en l’occurrence une demi-heure). La “plainte” ne prend effet que si la clé est remise immédiatement dans le boîtier avec verrouillage. Le système marque le véhicule comme défectueux et le retire de la liste. Le cas échéant, le client précédent est informé par un courrier (édité par l’employé) de son inadvertance et est interdit de location pour une durée donnée. De même, le plein lui sera facturé.

En cas d’accident ou de panne, le client informe directement par téléphone l’employé qui prend en charge le rapatriement ou la réparation. Régulièrement, l’employé note l’état des véhicules afin de relever les possibles incidents causés par les clients (égratignures, bosses, etc.), la liste des emprunteurs étant toujours connue, les responsables peuvent éventuellement être recouvrés. Enfin, l’employer édite les factures en fin de mois. Un protocole est aussi réalisé quant aux accès au parc. Les clients qui accèdent sont enregistrés qu’ils empruntent ou non un véhicule. Pour quitter le parc ils n’ont pas à utiliser leur badge pour des raisons de sécurité, mais néanmoins une ouverture de porte de l’intérieur est enregistrée dans le protocole.

D’autres traitements particuliers doivent être considérés : le client ne retire pas la clé dans un délai donné (un quart d’heure), le client dépasse une durée limite de location (une semaine), le client essaie d’emprunter une seconde voiture sans avoir “rendu” la première, etc.

Identification des acteurs et des cas d’utilisation

Nous identifions les acteurs suivants du système :

l’employé : c’est lui qui fait office d’administrateur. Il gère la base données. le client : il entre en contact avec le système à plusieurs niveaux : il accède au

parc, il utilise un PC avec accès restreint à la base et il retire et remet les clés de véhicule en place.

(32)

Les cas d’utilisation du système sont les suivant :

• le client effectue une location ;

• l’employé gère la base ;

Chacun de ces cas d’utilisation inclut un point commun, qui est l’identification. Nous en déduisons le diagramme des cas d’utilisation suivant :

Nous pouvons dors et déjà préciser les différentes instances de cas d’utilisation pour le client et l’employé :

• le client entre dans le parc en présentant son badge ;

• le client quitte le parc ;

• le client effectue une demande de location ;

• le client retire la clé d’un véhicule ;

• le client restitue la clé d’un véhicule ;

• le client constate un défaut sur le véhicule et le restitue sans location ;

• l’employé gère la base de clients : ajout, consultation, modifications, etc. ;

• l’employé gère la base de véhicules : ajout, consultation, mise à jour, etc. ;

• l’employé consulte le protocole d’accès au parc de voiture ;

• l’employé édite des courriers (facture, problèmes, etc.) ;

Dans les diagrammes de séquences et de collaboration nous allons développer certaines de ces instances de cas d’utilisation. Nous allons également aborder le problème de la gestion des données (base de données) à l’aide du diagramme des classes.

client employé Car-sharing effectuer location gestion BD identification <<inclut>> <<inclut>>

(33)

Diagrammes de Séquences

Chronologie de l’envoi de messages (scénarios)

Un diagramme de séquences représente une instance d’un cas d’utilisation. Il montre sous forme de scénario la chronologie des envois de messages issus d’un cas d’utilisation. Il fait donc intervenir les acteurs, mais également les objets, ainsi que des messages (les objets peuvent se réduire à l’objet système auquel cas on décrit un scénario d’interfaçage avec le système).

Un objet est représenté par un rectangle et une ligne verticale, appelée ligne de vie de l’objet. Les objets communiquent en échangeant des messages représentés par des flèches, orientées de l’émetteur vers le récepteur (destinataire). L’ordonnancement horizontal des objets importe peu. Il est choisi de façon à rendre le diagramme le plus lisible possible. L’ordonnancement vertical des messages indique la chronologie. Exemple de représentation :

1.

Généralités

On peut représenter explicitement la période d’activité d’un objet. Une période d’activité correspond au temps pendant lequel un objet fait une action :

:A :B :C

Message 1

Message 2

objet : Classe activation

(34)

On peut distinguer généralement trois types principaux d’envoi de message : • Flot de contrôle à plat : ceci indique une progression vers la prochaine étape

d’une séquence. Normalement ces types de messages sont asynchrones. La flèche est ouverte, comme sur les figures précédentes.

• Flot de contrôle emboîté (appel de fonction ou procédure) : il s’agit d’un

message plus “informatique”. La séquence emboîtée doit se terminer pour que la séquence englobante reprenne le contrôle.

On peut représenter explicitement le retour d’une fonction :

On peut également représenter la récursivité et la réflexivité :

:A :B :C procédure Sous-procédure :A :B val :=fonct() :A :B fonct() val :A récursion :A Message réflexif

(35)

• Retour d’un appel asynchrone de procédure : Le retour de procédure est

implicite à la fin d’une activation. Il peut être néanmoins utile de montrer explicitement la fin d’un appel asynchrone

2.

Création et destruction d’objets

Un message peut explicitement créer un objet, ou inversement un objet peut “se suicider”. La représentation graphique de la destruction est une croix en fin de ligne de vie :

3.

Structures de contrôle

Un diagramme de séquence peut inclure un certain nombre de structures de contrôle comme le branchement conditionnel et la répétition. Soit X une condition donnée. Voici les représentations possibles pour le branchement conditionnel :

A B A création A A B C [X] non [X]

(36)

Si la condition s’applique au même objet :

La boucle conditionnelle se note comme le branchement conditionnel avec une * pour montrer la répétition :

4.

Etude de cas : car-sharing

Nous n’allons pas dans le cadre de ce cours nous attarder à représenter tous les diagrammes de séquences, mais uniquement quelques uns d’entre eux.

A B [X] non [X] A B *[X] calcule() utilisateur : système

présente son badge

vérifier droit d’accès [accès OK] voyant vert

[ !accès OK] voyant rouge

(37)

L’exemple précédant concerne l’accès au parc par un client. Nous avons utilisé des envois de message sans évoquer les objets. Ce type de diagramme présente un scénario qui a pour vocation de spécifier une interface utilisateur / système.

Voyons une autre instance de cas d’utilisation : celui de la consultation de la liste de véhicules par l’employé pour mise à jour. Nous allons cette fois introduire des objets :

utilisateur

: EcranApplication : FormVehicule v: Vehicule

Demande consultation véhicules

: BD li :=ListeVehicule() affichage(li) Sélection véhicule id v:=RechVehicule(id) creation(v) creation() modifications enregistrer(v,id) modifier() Confirmer et terminer

(38)

Diagrammes de Collaborations

Caractériser les interactions entre objets

Les diagrammes de collaboration tout comme les diagrammes de séquence représentent une vue dynamique du système. Ces diagrammes identifient les interactions entre objets. Par rapport aux diagrammes de séquences, ils montrent plus la structure spatiale de l’interaction (plutôt que le séquencement).

5.

Généralités

Une collaboration définit les éléments nécessaires à la réalisation d’une opération ou d’un classificateur (classe, cas d’utilisation, etc.) dans un contexte donné. Elle possède deux types de descriptions :

a. Une description générale au niveau spécification qui représente :

i. les rôles des classificateurs et les rôles des associations ;

ii. une interaction : une séquence de messages partiellement

ordonnés échangés entre les rôles des classificateurs.

b. Une description spécifique au niveau instance qui représente :

i. une instance particulière d’une interaction avec les objets, les

liens et les instances de messages échangés entre objets.

Les collaborations s’emploient selon leur niveau de détail pour décrire des spécifications et exprimer des réalisations.

6.

Représentation au niveau spécification

La représentation des collaborations au niveau spécification forme un graphe de rôles de classificateur liés à des rôles d’association. Si aucune interaction n’est ajoutée, le diagramme représente simplement un contexte. Notation pour les rôles :

Rôle anonyme de classe Rôle R de class

Rôle R

Objet anonyme, rôle R Objet O, rôle R :C /R :C /R /R :C O/R :C

(39)

Exemple de diagramme de collaboration pour le cas de la location de logements :

Dans ce diagramme, nous avons précisé les rôles de deux personnes : locataire et propriétaire. Ce diagramme ne montre cependant pas d’instance de collaboration.

7.

Représentation au niveau instance

La représentation des collaborations au niveau instance est un graphe d’instances qui se conforme au rôle des classificateurs et des associations définies au niveau spécification. Des messages peuvent s’ajouter à ce graphe. Les acteurs apparaissent également dans ce graphe et déclanche des opérations.

On peut mettre en évidence des interactions entre objets en les reliant. Ces interactions peuvent correspondre à la création locale d’instance (transition), à la création tout court ou à la destruction. Les messages circulent entre acteurs et objets interagissant.

/ locataire:personne :logement / propriétaire:personne :lieu :baille :coût * 1 +habitant * 1 1 1 * 1 * 1 1 1 1 1 +adresse +loyer

(40)

Exemple de diagramme de collaboration pour le cas de la location de logements :

Il n’est pas nécessaire en général de préciser les rôles comme ici l’objet Bailleur qui joue le rôle de propriétaire.

8.

Envoi de messages

Comme pour le diagramme de séquences, on distingue trois types de messages :

• Appel de procédure ou flot de contrôle emboité :

• Flot de contrôle asynchrone :

• Flot de contrôle à plat. Il s’agit généralement de messages échangés entre

acteurs et systèmes ou parties de systèmes communiquant (deux composants physiques différents ou distants) :

Les messages sont numérotés : 1, 1.1 (pour les sous-messages liés à 1, puis 1.1.1 ou 1.1.1a et 1.1.1b s’il y en a en même temps, ou bien 1.1.i, etc. La multiplicité d’instances se représente par plusieurs “fiches” (comme dans :logement du diagramme précédent).

prop:personne Bailleur / propriétaire :personne :coût :logement 1 : revenuDeLocation(lesLogements) 1.1 : *[i :=1..n] : loyer() 1.1.i : valeur()

(41)

Pour l’envoi de messages, on retrouve des structures de contrôle similaires aux diagrammes de séquences : • itération : • condition s • paramètres

9.

Représentation condensée

La collaboration est une réalisation de cas d’utilisation. Nous avons déjà vu dans le chapitre précédent qu’elle pouvait se représentée de manière condensée par une ellipse en pointillés. On peut utiliser cette écriture pour préciser la réalisation spécifique d’une opération de classe :

10. Etude de cas : car-sharing

Comme pour le cas des diagrammes de séquence, nous n’allons pas développer ici l’ensemble de toutes les instances de cas d’utilisation.

:A *[i :=1..n] Message :B :A [x>y] Message :B :A :B Message args retour Personne +calculeRevenuLoyer() Calcul du Revenu

Références

Documents relatifs

Point p2=p1 ; // constructeur de recopie : création de l’objet p2 // et son initialisation avec les données de p1.. Attention : il faut différencier entre recopie et

Comme dans le cas d’une méthode, si le code est très court, on peut directement mettre le constructeur dans la déclaration de la classe (définition en ligne). Exemple :

Cette technique permet de sécurisé l’accès aux données en vérifiant par exemple des conditions de valeur ou d’accès et permettant une plus grande flexibilité du coeur des

Donner des noms explicites (classes, méthodes, attributs) Développer une documentation du code (cf cours

Dans le cas de l’approche procédurale, un programme correspond à l’assemblage de plusieurs fonctions qui s’appellent entre elles. Exemple de langages de

‣ la classe ArrayList&lt;E&gt; encapsule un tableau d’objets et en gère les aspect dynamique. ‣ par rapport

 cette classe doit contenir une référence vers le panel de dessin pour pouvoir agir sur ses figures, ainsi qu’une référence vers le panel des icônes pour récupérer la figure

● Il est considéré comme sain de passer par des sélecteurs pour accéder à la valeur du champ d’un objet plutôt que d’accéder directement à cette valeur avec la