Analyse et Conception UML Simplifiée
Analyse et Conception UML Simplifiée
et de conception
avec le langage
UML
Je tiens à remercier mon chat et mon poisson rouge ( jusqu'à ce que mon chat ne le mange )
pour l'aide et le soutien moral qu'ils m'ont apportés.
Cette démarche de conception est la démarche proposée par Craig LARMAN. Je l’ai connue à
travers le cours “Analyse et conception avec UML et les Patterns " de la société Valtech.
J’ai ici repris cette démarche, je l’ai légèrement simplifiée, et j’ai apporté les informations
nécessaires pour que des stagiaires de l’AFPA puissent s’imprégner de cette démarche.
Dans un premier temps j’ai repris l’exercice du cours Valtech. Souhaitons qu’il y ait un
deuxième temps …
Les formateurs qui désirent former leurs stagiaires à cette démarche devraient suivre le cours
pré cité, afin de prendre du recul par rapport à la démarche.
Le but de cette démarche est d’analyser et de concevoir une application objet. L’objectif est
d’avoir une application qui puisse vivre ( évolution de l’application dans le temps ), et qui
enrichisse la base de savoir-faire de l’entreprise ( développement de nouveaux applicatifs en
s’appuyant sur des objets métiers déjà développés ) . La réutilisabilité est un des soucis
principaux pour pouvoir réduire le coût des logiciels et augmenter la puissance de
développement des programmeurs.
Nous nous appuierons sur le workflow, c’est à dire les règles des processus métier pour
débusquer les uses cases, et les acteurs. Dans l’analyse et la conception objet nous cherchons
à construire une architecture en couche de la forme suivante :
Nous verrons que chaque couche définira un ou des contrôleurs pour la rendre
indépendante des autres.
Une étude a montré que dans certaines entreprises les règles métier changeaient de 10%
par mois ! ! ! Il est facile de comprendre alors la raison de ce découplage des objets
métiers. Les objets ont tendance à être stables dans le temps, par contre les IHM et base de
données peuvent également être changées sans que l’on touche au métier ni aux règles de
l’entreprise.
Cette architecture ne s’appliquera bien sûr pas à toutes les applications, c’est à prendre
comme un exemple complet.
Lister l’ensemble des exigences du client issues du cahier des charges, ou issu d’une
démarche préalable de collecte d’information ( documents électroniques, notes de
réunions, notes d’interviews, … ). Chaque exigence sera numérotée et ainsi pourra être
tracée.
Deux solutions possibles :
Nous allons regrouper les exigences par intentions d’acteur complètes puis nous
allons faire un diagramme de contexte ( nous nous appuierons sur un diagramme de
collaboration pour cela )
Si toutes les règles de processus métier sont définies, nous réaliserons un diagramme
d’activité en colonnes ( "swim lane" ) où les colonnes sont les acteurs. Cela permet de
dégager les responsabilités de chaque acteur, et ainsi de connaître les intentions des
acteurs.
Définir les uses cases et construire le diagramme de uses cases.
Faire la description de haut niveau de chaque use case : chercher des scénarios de base.
Faire la description détaillée de chaque use case : donner les séquences nominales puis
les séquences alternatives ( Erreurs et exceptions, en limitant au maximum les
exceptions). Cette description peut être complétée par un diagramme d’activité qui montre
le séquencement des différents scénarios.
Cette description détaillée comprend les scénarios, les pré conditions, à partir de quoi se
déroule le use case, comment se termine le use case, et enfin les post conditions ( règles
métier assurées quand le use case est terminé).
Faire un diagramme de séquence par scénario ( ici c’est un diagramme de séquence boîte
noire, où la boîte noire correspond au système informatique à développer ).
Faire un diagramme de classe par use case. Le diagramme de classe final sera la
superposition de ces diagrammes de classe.
Les classes obtenues sont des classes du monde réel.
Nous ne mettons pas les opérations car nous ne connaissons pas l’intérieur du système
informatique.
Un contrat est réalisé pour chaque opération du système. Ce contrat contient un nom, des
responsabilités, les exigences auxquelles répond notre itération de cycle de vie, les pré
conditions, et les post conditions ( décrites sous la forme " has been " ) et enfin les
exceptions.
Ce contrat peut être réalisé sous forme textuelle, ou plus souvent sous forme d’un
diagramme de séquence boîte blanche où les objets échangent des messages pour rendre le
service demandé.
A partir des diagrammes de classe et des contrats nous réaliserons les diagrammes de
collaboration qui montrent comment les objets collaborent pour rendre le service
demandé. Nous appliquerons les patterns de conception pour cela ( GRASP patterns )
En parallèle nous réaliserons les diagrammes d’état des objets les plus complexes, ainsi
nous détecterons des méthodes internes à ces objets.
B
E
S Diagramme de uses cases Use case haut niveau
O
I
N
S
nom : effectuer un achat
acteur principal : client :caissier :magasin
acteur secondaire : caissier
événement déclencheur : …
rôle du use case : …
terminaison du use case : …
références croisées : …
pré conditions : …
A scénarios et alternatives : …
N
A Use case bas niveau Diagramme de séquence
L
Y
S
E nom : …
responsabilité : …
exigences : …
notes : …
pré conditions : …
post conditions : …
C
O
N 1 : m() :o1
C
E
P 1.1 : msg()
T
I :o2
O
N
Diagramme collaboration Diagramme de classe de conception
ref fonction
R1 payer achat
… …
0..*
payer
retourner est dans
magasin
0..1
magasin
:caissier :magasin
repérer les
classes
mettre méthodes
mettre les et attributs
associations
nom : …
responsabilité : …
exigences : …
notes : …
pré conditions : …
post conditions : …
Contrat d’opération
attente
actif
Diagramme d’état
1.1 : msg()
:o2
Diagramme collaboration
Nous allons traiter l'ensemble de la démarche d'analyse objet sur un même exemple. Cet
exemple a été pris dans la littérature ( voir la bibliographie ). Nous ne traiterons pas
l'ensemble de l'exemple, mais l'ensemble de la démarche.
Chaque type de produit est référencé dans un catalogue, avec son prix associé. Quand le prix
d'un produit doit être modifié, le manager modifie son prix dans le catalogue, puis sur
l'étagère où il est rangé.
La caisse fera les fonctions habituelles d'une caisse : calcul du sous total, calcul du total,
possibilité de rentrer plusieurs articles ayant un même code, retour d'une marchandise avec le
ticket de caisse. Le paiement se fera en monnaie seulement.
La caisse s'exécute sur un PC. Une douchette permettra de lire les codes à barres. Les
informations peuvent être rentrées au clavier, ou à la souris.
La définition des besoins démarre avec le début du projet. Elle a pour but d'obtenir un premier
jet des besoins fonctionnels et opérationnels du client. Dans cette phase nous collectons des
informations pour définir le besoin du client.
A l'issue de cette étape, nous aurons mis textuellement ou à l'aide de schémas très simples,
notre compréhension du problème à traiter sur le papier.
Le client doit être capable de valider l'étude ainsi faite. Elle lui est donc accessible.
Les exigences que nous allons découvrir sont les exigences fonctionnelles. A partir du
problème posé, c'est à dire de tout ce qui est écrit, plus tout ce qui ne l'est pas, nous allons
lister l'ensemble des fonctions qui pourront être réalisées par le logiciel. Ces exigences seront
numérotées pour pouvoir les tracer dans les intentions d'acteur puis dans les uses cases.
Référenc
Fonction
e
R1 Modifier le prix d'un produit
R2 Calculer le total d'une vente
R3 Rentrer une quantité par article
R4 Calculer le sous total d'un produit
R5 Retourner une marchandise
R6 Payer l'achat
R7 Editer un ticket de vente
R8 Editer un rapport succinct
R9 Editer un rapport détaillé
R10 Se connecter à la caisse
R11 Se connecter en gérant
R12 Définir les droits des usagers
R13 Entrer un produit au catalogue
R14 Supprimer un produit du catalogue
R15 Enregistrer un produit à la caisse
R16 Initialiser la caisse
La modification du prix sur une étagère n'est pas traitée par le système. Donc ce n'est pas une
exigence fonctionnelle pour notre logiciel.
Définir les droits des usagers n'est pas indiqué dans le texte, mais est nécessaire au bon
fonctionnement du logiciel.
Le PC ainsi que la douchette sont des exigences d'architecture, elles ne seront pas prises en
compte ici.
Entrer et supprimer un produit du catalogue sont des fonctions tellement évidentes que le
client n'en parle pas. Elles doivent cependant être intégrées au logiciel.
Les informations rentrées au clavier ou à la souris sont des exigences d'interface qui seront
prises en compte ultérieurement.
Les acteurs seront vus dans le sens processus transversal de l'entreprise ( workflow ). Préférer
un acteur humain plutôt que le dispositif électronique devant lequel il est. L'acteur humain a
bien une intention quand il fait quelque chose. Un dispositif électronique beaucoup moins en
général.
: Client : Caissier
retourner un article
payer un achat
gérer le catalogue
initialiser les caisses
magasin editer des rapports
se connecter
: Manager
: Salarié
: Administrateur
Ce diagramme est un diagramme de classe qui permet de lister les différents acteurs. Il se peut
Diagramme de contexte du magasin
que notre liste ne soit pas complète, une itération suivante du processus nous permettra de
compléter ce schéma.
Nous avons défini 5 acteurs. N'oublions pas qu'un acteur représente un rôle, et non pas une
personne.
Nous connaissons les acteurs, et les exigences de l'application. Nous pouvons donc faire un
diagramme de contexte dynamique. Ce diagramme de contexte qui définit les interactions
entre les acteurs et le système ( pas encore système informatique car nous en sommes au
processus métier donc à découvrir les uses cases ) sera réalisé en UML par un diagramme de
collaboration. Il représente le fonctionnement de l'entreprise. Ici nous ne préciserons pas
forcément l'ordre et le séquencement des opérations.
0..*
Client 1
Caissier
(from Use Case View) (from Use Case View)
0..1
0..1
magas in
0..*
gère
travaille dans 1..* 0..*
0..* administre
1
1 Manager
Salarié
(from Use Case View)
(from Use Case View)
administrateur
(from Use Case View)
Nous allons maintenant regrouper les exigences en intentions d'acteurs. Une intention
d'acteur est un enchaînement de fonctions qui rend un service complet à un acteur ( et pas une
fraction de service ).
Ici dans le tableau la notion d'acteur repose sur l'intention d'acteur, pas sur la fonction. Ainsi
toutes les lignes d'une même intention d'acteur ne sont-elles pas renseignées pour les acteurs.
Ici nous distinguerons l'acteur principal des acteurs secondaires en soulignant l'acteur qui est à
l'origine de l'intention.
Nous allons bien sûr vérifier que les exigences définies précédemment sont toutes incluses
dans les intentions d'acteur. La traçabilité est un facteur essentiel des phases de définition des
besoins et de celle d'analyse.
Nous avons les intentions d'acteurs, nous pouvons donc faire un diagramme de Use Case.
Un use case est une intention d'acteur. Quand un acteur démarre un use case, il a une intention
précise. Quelle est cette intention? Effectuer un achat est une intention qui recouvre un certain
nombre d'exigences. C'est une unité d'intention complète d'un acteur: c'est donc un use case.
Payer ses achats n'est pas une intention complète d'acteur. Nous n'allons pas dans un magasin
pour payer, mais bien pour faire des achats. C'est donc une partie ( et pas la plus agréable ) de
effectuer un achat. Ce n'est donc pas un use case.
L'acteur déclencheur de l'achat est le client. C'est lui qui est venu effectuer un achat.
Effectuer un achat
Client
Retourner un article
les
Lesflêches
flèchesunidirectionnelles
unidirectionnelles
Caissier indiquent un lien principal,
Se connecter indiquent un lien principal, c’est à
c'est à dire l'acteur principal du
dire l’acteur
use case. principal du use case
Gérer le catalogue
Salarié
Manager Initialiser la caisse
Editer un rapport
administrateur
Définir les profils
Un tel use case ne peut être lié qu'à un use case, pas à un acteur. ( nous mettrons alors le
stéréotype include sur le lien use case vers use case subalterne ).
authentification
Un use case peut nécessiter le service d'un autre use case. Le use case dont nous avons
besoin du service étend le use case demandeur. Nous utiliserons le stéréotype extend. Ici
les uses cases peuvent être sollicités par des acteurs.
<<extend>>
Retrait
Ces spécialisation, include et extend ne se mettent bien souvent pas dans le premier cycle de
développement, car c'est l'étude de l'application qui mettra en évidence ces caractéristiques.
Nous verrons plus tard ces notions de cycle dans le déroulement d’une démarche comme
celle-ci.
Il nous faut maintenant définir les uses cases. Cette description est une description de haut
niveau qui se fait avant l'analyse. Nous sommes toujours dans la définition du besoin.
Une description de haut niveau d'un use case est une description textuelle qui comprend les
chapitre suivants:
Cette description est assez succincte 3 ou 4 lignes maximum pour le rôle du use case. C'est
une description narrative d'un processus métier. Cette description ne repose pas sur la
technologie objet.
Les cas d'utilisation ( autre nom pour un use case ) vus dans l'analyse sont dits essentiels. Ici
nous ferons donc la description de cas d'utilisation de haut niveau essentiels.
Essentiel signifie que l'on ne fait pas référence à la technologie, que le use case décrit le cœur
du métier, ils sont appelés use case pour 100 ans. De haut niveau veut dire que l'on en fait une
description brève, sans entrer dans le détail du séquencement du use case.
Nous verrons par la suite des uses cases détaillés ( en phase d'analyse ), et des uses cases réels
( en phase de conception ).
Après une première ébauche des besoins des clients, il va falloir approfondir ses besoins,
examiner les différents scénarios des uses cases ( éventuellement avec un diagramme
d'activité pour exprimer ces différents scénarios ), tenir compte des traitements exceptionnels
et cas d'erreur. Il va être nécessaire de regarder le séquencement des opérations d'un point de
vue fonctionnel, pour voir comment les différents acteurs interagissent avec le logiciel, à
l’aide des diagrammes de séquence boîte noire ( la boîte noire c'est le système informatique à
développer ). Il est alors nécessaire de distinguer les différents objets qui collaborent dans
notre système informatique ( avec un diagramme de classe ). Enfin nous allons détailler le
rôle des opérations en définissant des contrats d'opération ( soit sous forme textuelle, soit sous
forme de diagramme de séquence ). Nous aurons alors tous les éléments pour passer à la
conception.
Nous n'avons ici comme souci que de détailler les besoins du client pour s'en imprégner, afin
de pouvoir le formaliser et le préciser.
La description complète du use case donne la priorité aux choses que les acteurs perçoivent.
Nous décrirons les actions des acteurs en commençant par l'acteur principal qui initie le use
case, puis nous donnerons les réponses du système ( vu comme une boîte noire ). Le premier
travail se fait sur un cas nominal ( c'est à dire idéal ). Les cas d'erreur ( avec correction et
reprise ) et les exceptions ( avec abandon du use case ) sont traités ensuite.
Le formalisme est textuel et prend la forme suivante:
En premier lieu nous voyons les échanges entre le système et les acteurs, ainsi que la
chronologie et l'enchaînement des actions, dans le cas nominal.
Dans un deuxième temps nous listons les cas d'erreur ( avec traitement de récupération ) et les
traitements d'exception avec arrêt du use case.
Nous restons bien fonctionnel car nous ne décrivons pas comment est réalisé le système, mais
comment sont réalisés les services qu'il rend.
Notion de scénario: un use case est un regroupement d'actions plus élémentaires qui permet de
traiter une intention d'acteur assez générale. Un scénario est une réalisation du use case, donc
une "intention élémentaire". Par exemple pour une gestion de compte client dans une banque,
nous avons un use case gérer les comptes. Nous avons plusieurs scénarios: créer un compte,
consulter un compte, modifier un compte, …
Pour chacun des scénarios il va falloir faire une description détaillée de use case ( avec
traitement d'erreur et d'exception pour chacun ). Un diagramme d'activité va permettre de
montrer l'ensemble d'un use case, en regroupant l'ensemble des scénarios de ce use case.
Evénement déclencheur du Use Case: Un client arrive à la caisse avec ses achats
Rôle du Use Case: Le caissier passe tous les articles, fait la note, et
encaisse le paiement.
Les références croisées des exigences: R2, R3, R4, R6, R7, R15
Les pré conditions nécessaires au fonctionnement du use case: La caisse est allumée et
initialisée. Un caissier est connecté à la caisse.
Ici il n'y a qu'un scénario possible. Nous verrons dans l'exemple suivant un use case avec
plusieurs scénarios pour mettre en évidence le diagramme d'activité.
Variantes du scénario nominal ( celui qui se déroule quand tout se passe bien ).
Paragraphe 2: il peut y avoir plusieurs articles d'un même produit. Le caissier enregistre le
produit ainsi que le nombre d'articles.
Paragraphe 3: s'il y a plusieurs articles d'un même produit le système calcule le sous total.
Paragraphe 2: Le code produit peut être invalide. Le système affiche un message d'erreur.
Paragraphe 7: Le client n'a pas la somme d'argent suffisante. La vente est annulée. Remarque:
Ceci est une exception qui termine anormalement le use case.
Paragraphe 8: Le caissier n'a pas la monnaie pour rendre au client. Il va faire la monnaie à la
caisse principale. Remarque: ici nous avons fait apparaître un nouvel acteur: le caissier
principal ( ce sera probablement la même personne que le manager mais un acteur différent ).
Paragraphe 12: le système ne peut pas éditer le ticket de caisse. Un message est affiché au
caissier, et celui-ci change le rouleau de papier.
Paragraphe 14: remarquons que si le client repart sans ses articles, il est probable que le
caissier les lui mettra de coté. Cet événement ne change rien à notre système futur. Ce genre
d'incident ne sera pas pris en considération.
Cette représentation met en évidence que le client n'a pas accès au système informatique.
Contraintes non fonctionnelles ( optionnel ): Le magasin reçoit en moyenne 200 clients par
jour. Chaque client achète en moyenne 10 articles.
supprim er un
article
détruire la référence
modifier le prix
d'un article
ajouter un
article
réalis ation d'un diagram me d'activité ( ici ce n'est pas la norm e UML car la version
de ros e utilis ée ne supporte pas les diagram mes d'activité ). Ce s chém a a été
construit à partir d'un diagramm e d'état.
Les uses cases ont été validés par le client. Nous allons donc changer notre point de vue
( workflow c'est à dire processus métier ) pour adopter un point de vue système informatique.
Nous abandonnons donc les événements métier pour nous intéresser aux événements
informatiques.
Nous allons développer un diagramme de séquence par scénario de use case détaillé. Ces
diagrammes de séquence sont dits boîte noire car nous ne savons toujours pas comment sera
fait le système informatique. Ici nous précisons les échanges entre les acteurs utilisateurs du
système informatique et le système proprement dit.
Les interactions des acteurs directement sur le système sont appelées des événements. Les
actions engendrées par le système suite à ces événements sont appelées des opérations. A un
événement correspondra une opération. Dans la terminologie message et événement sont
équivalents entre eux, ainsi que méthode et opération.
Les diagrammes de séquence seront agrémentés de notes et commentaires qui permettront
d'illustrer le diagramme: explication de contrôles, itérations, logique, choix, …
Rappelons qu'un diagramme de séquence boîte noire est de la forme:
retour de la demande
logout()
de login OK
événement
Les valeurs de retour se formalisent de différentes manières suivant la version d'UML choisie.
Ici j'ai pris un exemple de notation la plus simple possible. Attention à ne pas confondre avec
un événement ( sens acteur vers système informatique ).
En fin de phase nous connaissons les échanges entre les utilisateurs et le système
informatique. Nous pourrions construire une maquette des écrans pour les acteurs.
Formellement nous le ferons en phase de conception. Notre maquette d'écran serait une
maquette "fonctionnelle" ( c’est à dire que le dessin de l’écran n’est pas figé ).
pour chaque
article enregistrer un article ( code )
fin de vente ( )
payer ( somme )
monnaie
ticket
ici la réponse
est asynchrone
Le diagramme de classes est un des documents les plus importants, voire le plus important de
l'analyse d'un logiciel par une méthode objet. C'est le premier document qui est dans le monde
des objets ( les acteurs n'étant pas forcément représentés dans le système informatique ). C'est
donc l'entrée dans le monde des objets.
Ce diagramme est un diagramme de classe d'analyse. Il ne représente pas les classes Java ou
C++ que nous développerons par la suite.
Ici nous nous intéressons aux classes du domaine métier, c'est à dire des objets dont on parle
dans le cahier des charges et dans les uses cases principalement. Nous ne nous intéressons pas
aux objets informatiques dans ce diagramme ( sauf bien entendu si le métier est l'informatique
!! ). Cela viendra en son temps, dans le diagramme de classe de conception. Quand nous
passerons à la conception des classes disparaîtront, d'autres apparaîtront, dont les classes
informatiques ( collections, … ). C'est normal. En phase d'analyse, nous voulons simplement
faire un diagramme de classe d'objets manipulés dans le domaine métier considéré.
Dans ce diagramme de classe les opérations ne sont pas représentées ( ce sera lors de la
conception ).
Ce diagramme montrera les concepts du domaine métier, les liens ( associations ) entre ces
concepts ( avec leur cardinalité ou multiplicité ), et les attributs de ces concepts ( souvent sous
forme de données simples ).
Le but de ce diagramme est de clarifier le domaine métier du client, et de se familiariser avec
ce domaine.
Dans une analyse structurée nous décomposons l'analyse suivant les tâches ou les fonctions.
Dans une application à dominante gestion, nous décomposerons notre application suivant les
données, et les traitements. Ici nous analyserons la complexité du domaine en regardant les
objets métier et leurs interactions entre eux.
Comment identifier les bons objets métier pour construire notre diagramme de classe
d'analyse?
Il va falloir recenser dans les documents de définition des besoins et dans les documents
d'analyse l'ensemble des objets métier.
Les noms ou groupes nominaux vont être de bons candidats pour être élus au titre de classe,
objet ou attribut. Cependant, il faut être prudent car il y aura aussi un certain nombre de faux
amis et de doublons.
Pour un use case nous recenserons les groupes nominaux rencontrés. Nous identifierons alors:
Les classes ( noms communs ).
Les objets ( noms propres ou nom référencés ).
Les attributs ( données simples qui qualifient une classe ou un objet ).
Les éléments qui sont étrangers à notre problème ou qui n'y ont pas de rôle réel.
Il est parfois difficile de savoir si une information est un attribut d'une classe ou une classe
( avec une association avec la classe ). Dans le doute il vaut mieux faire une classe, quitte à
revenir en arrière dans une itération ultérieure. Par exemple pour la classe personne l'âge est
un attribut ( donnée simple ) l'adresse étant à priori une donnée complexe sera plutôt une autre
classe associée à la personne.
Pour le use case " effectuer un achat " voici la liste des classes sélectionnées:
caissier
Magasin
caisse
Paiem ent
catalogue
vente
ticket
article
ligne de vente
description article
Nous noterons ici la décomposition entre article et description article, car la description article
est unique pour tout un ensemble d'articles. D'autre part quand un article est en rupture de
stock, la description de l'article existe toujours, bien qu'il n'y ait plus d'article en magasin.
Nous allons maintenant rajouter les associations entre les classes, en donnant un intitulé et des
cardinalités à ces associations.
caissier
0..1
catalogue
utilise
1 1 1
0..1
caisse
se fait à partir
1 possède
1
Paiement 1 effectue
payée par 0..1 Magasin
1 1
vente 1
contient
génère 1 1
contient
0..* décrit
1 0..* 1
description article
Sur ce diagramme de classe d'analyse il faut maintenant mettre les attributs des classes qui ont
été repérés dans le cahier des charges, le diagramme de use case, ou dans le diagramme de
séquence boîte noire du use case.
A priori, les attributs présents dans notre diagramme de classe d'analyse sont des attributs
simples. On pourra faire exception des données pures qui sont des regroupements de données
simples ( ici code, adresse, prix ) .
caissier
0..1
catalogue
utilise
1 1
0..1 1
caisse
se fait à partir
possède
1
1
Paiem ent
effectue Magasin
somm e : réel 1 0..1
payée par 1 nom : text
1 vente adresse : Adresse
date : Date
heure : Heure 1
génère contient contient
1
1
ticket
1 comprend 0..*
article
1..*
1..* référence
1
ligne de vente 0..*
quantité : entier
décrit
0..*
le prix ou la
somm e devraient est décrite par
0..* 1
se donner par 1
rapport à une description article
monnaie...
description : text
prix : réel
code : codebarre
Le glossaire répertorie tous les termes et leur définition. Il n'y a pas de graphisme particulier
pour ce document. Il peut être fait sous la forme suivante:
Nous allons maintenant étudier ce qui est fait dans le système, pour chaque flèche qui attaque
le système dans les diagrammes de séquence.
Notre but est de comprendre la logique de fonctionnement du système. Les flèches
représentées dans les diagrammes de séquence boîte noire déclenchent des opérations sur le
système. Nous allons donc définir précisément le rôle de ces opérations en nous appuyant sur
le diagramme de classe ( appelé aussi modèle de domaine ). C'est ce qui s'appelle des contrats
d'opération.
Le système informatique a été vu comme une boîte noire ( en particulier à travers les
diagrammes de séquence ). Il serait, d'un point de vue fonctionnel, intéressant de décrire ce
que fait le système, en se basant sur le diagramme de classe, sans pour autant décrire
comment il le fait. Les contrats d'opération vont nous permettre de décrire les changements
d'états du système ( c'est à dire les changements sur les objets et leurs associations ) quand les
opérations ( issues des diagrammes de séquence ) sont invoquées par les acteurs.
Un contrat d'opération est un document textuel qui décrit les changements provoqués par une
opération sur le système. Le contrat d'opération est écrit sous forme textuelle et comporte des
pré conditions et des post conditions. Les pré conditions décrivent l'état du système nécessaire
pour que l'opération puisse s'effectuer. Les post conditions décrivent l'état du système lorsque
l'opération s'est achevée.
Les Pré conditions décrivent l'état du système, c'est-à-dire l'état des objets du système comme
décrit dans le diagramme des classes d'analyse.
Nous jouons l'opération sur le système, en aveugle, et jusqu'à sa fin.
Notons les changements de l'état du système ( des objets et de leurs associations ) et nous
obtenons les post conditions. Ces post conditions sont décrites sous la forme "has been", c'est-
à-dire l'objet X a été modifié, son attribut Y a été mis à vrai.
Nous allons faire les contrats d'opération des opérations du use case effectuer un achat. Pour
cela il faut partir du diagramme de séquence boîte noire du use case effectuer un achat et du
diagramme de classe d'analyse, et pour chaque flèche dirigée vers le système, rédiger un
contrat d’opération. Par exemple :
Enregistrer un article.
Finir la vente.
Payer la vente.
Nous allons voir une autre manière de représenter ces contrats d'opération à l'aide de
diagramme de séquence boîte blanche. Cette manière de représenter les contrats d'opération
est beaucoup plus utilisée que la manière textuelle. Elle n'est pas forcément mieux d'ailleurs…
modifier(cecode, nouveauprix)
modifier( prix )
Maintenant nous allons faire les diagrammes de séquence boîte blanche des opérations du use
case effectuer un achat.
Diagramme de séquence boîte blanche de enregistrer un article.
da = selectionner( cecode )
create(da,1)
si nouvelle
vente
afficher(description,prix)
description,prix
la quantité
vaut 1
dénom brer(q)
ldv = sélectionner dernier ldv()
modifquantité(q)
p = getprix()
[Link]é*p
afficher([Link]é*p)
: caisse : vente
: Caissier
finir vente()
set terminé(true)
T = calculer Total()
setTotal(T)
Total Total
afficher
cela nécessite de
parcourir toutes les
lignes de vente
payer (s)
payer(s)
create([Link])
[Link]
afficher([Link])
create()
imprim er()
Ces schémas sont moins précis que le contrat d'opération sous forme textuelle. Nous n'y
retrouvons pas les associations. Les schémas de diagramme de séquence boîte blanche utilisés
pour décrire un contrat d'opération ( bien que souvent utilisés ) vont introduire des choix de
conception ( qui déclenche les opérations? ). Si ces choix ne sont pas faits le diagramme
induit une erreur d'interprétation. Nous préfèrerons donc faire ces choix de conception dans le
diagramme de collaboration, et garder le contrat d'opération sous forme textuelle.
Le diagramme d'état est à la frontière de l'analyse ( par la compréhension des cycles de vie de
certains objets ) et de la conception ( par les méthodes qu'il permet de définir dans les classes
étudiées ).
"Le diagramme se réalise pour les classes d'objets ayant un comportement significativement
complexe. Toutes les classes d'un système n'ont pas besoin d'avoir un diagramme d'état."
( James RUMBAUGH )
Si, dans l'analyse de notre système, des classes paraissent complexes, par exemple si elles
sont souvent sollicitées dans les diagrammes de séquence boîte blanche, il est bon de faire un
diagramme d'état de ces classes: cela permet d'avoir une vue orthogonale de la classe par
rapport à ses liens avec les autres classes. Ainsi, nous regardons le comportement des objets
d'une classe, et leur évolution interne au fil des événements. Cela nous donne le cycle de vie
des objets d'une classe.
Ainsi, ayant perçu le fonctionnement des objets d'une classe, il est plus facile de vérifier que
les objets des autres classes respectent bien ce comportement. Cela améliore notre perception
du problème.
Cela implique que les diagrammes d'état doivent être confrontés aux diagrammes d'interaction
afin de vérifier la cohérence de ces diagrammes.
Quelques rappels:
Un objet peut avoir une activité dans un état. Par exemple quand la caisse est en attente d'un
client, elle peut faire défiler un message de bienvenue sur l'écran client.
Un objet peut avoir des actions qui seront déclenchées sur des événements. Par exemple sur
l'événement fin de vente, la caisse va afficher le total à payer.
Une action est une opération atomique qui ne peut être interrompue.
Elle est considérée comme instantanée.
Elle est généralement associée à une transition.
Une activité est une opération qui dure et qui peut être interrompue.
nouvel article
im pression en cours
attente paiement
entry : lancer
im pression somm e saisie / afficher monnaie
Le diagramme de collaboration va nous montrer comment les objets interagissent entre eux
pour rendre le service demandé par le contrat d'opération. Nous allons d'abord observer la
syntaxe, et la forme que prend ce diagramme d'opération. Les objets doivent demander des
services à d'autres objets. Il leur faut donc connaître ces objets pour pouvoir leur adresser des
messages. Nous allons donc regarder la visibilité des objets ( c'est à dire comment un objet
peut connaître d'autres objets ). Enfin quand une ligne du contrat d'opération est réalisée il
faut se poser la question de savoir quel objet agit pour réaliser cette ligne ( qui crée tel objet,
qui reçoit l'événement initial). En un mot il est nécessaire de définir les responsabilités des
objets. L'expérience et le savoir faire des professionnels nous ont permis de définir des règles,
des modèles de pensée, qui nous permettrons de nous guider pour définir les responsabilités
des objets. Ce sont les GRASP patterns que nous verrons enfin, avant de traiter notre caisse.
Nous allons prendre un exemple de diagramme de collaboration pour introduire toutes les
notions véhiculées dans ce diagramme. Rappelons nous que ce diagramme, dans le contexte
de la conception, nous montre comment les objets coopèrent entre eux pour réaliser les
opérations définies par les contrats d'opération.
Modifierprix(code,prix) 1 :Modifierprix(code,prix)
:caisse :catalogue
1.2 : setprix(prix)
ta :Type article
:Type article
a) les objets
Ici nous représentons la coopération des objets pour rendre le service demandé. Il s’agit
donc bien d’objets. Ces objets apparaissent sous trois formes :
Objet
anonym
e
Modifierprix(code,prix) 1 :Modifierprix(code,prix)
:caisse :catalogue
Objet
1.2 : setprix(prix) Multi
nommé
objet
ta :Type article
:Type article
Message
initial issu
du Caisse envoie
diagramme un message à
de séquence catalogue
D’abord le
Modifierprix(code,prix) 1 :modifierprix(code,prix) catalogue
:caisse :catalogue
cherche le type
d’article
Puis il
modifie le
prix du
type trouvé
1.1 :ta := chercher(code) :Type article
1.2 : setprix(prix)
ta :Type article
:Type article
Les opérations effectuées en réaction à un message numéro x seront numérotées de x.1 à x.n.
Et ainsi de suite pour les opérations effectuées en réaction à un message numéro x.y ( x.y.1 à
x.y.n).
Valeur message
de retour
Type de
1.1 :ta := chercher(code) :Type article retour du
message
Paramètre(s)
numéro affectatio du message
n
Un lien entre deux objets est directionnel. La flèche indique le receveur du message. Ce lien
implique que l’objet qui envoie le message connaisse celui qui le reçoit. Un objet ne peut en
effet envoyer un message qu’à un objet qu’il connaît ( rappelez-vous que l’on envoie un
message à un objet en lui parlant : moncatalogue , modifie le prix de l’article de code
moncode à monprix.). Chaque flèche implique une visibilité orientée entre les objets.
:catalogue
connaît ta et
le multiobjet
Modifierprix(code,prix) 1 :Modifierprix(code,prix)
:caisse :catalogue
:caisse
connaît
l’objet 1.1 :ta := chercher(code) :Type article
:catalogue
1.2 : setprix(prix)
ta :Type article
:Type article
Nous avons vu la forme générale des messages. Il peut y avoir quelques formes particulières
de messages, que nous allons lister maintenant.
1 :msg() 1.1[x>y] :message()
:A :B
numéro conditio
n
Le message n’est envoyé à :B que si la condition x>y est remplie lors du déroulement du code
de msg() dans la classe A.
1 :msg() 1.1a[x>y] :messageb()
:A :B
Numéro conditio
avec une n
letrre
:C
Même numéro
avec une autre
lettre Condition
contraire
Si la condition x>y est vérifiée, un message est envoyé à l’objet :B, sinon un message est
envoyé à l’objet :C
Ce sont les messages de création d’objet. Ce sont des messages create, avec ou sans
paramètres, qui créeront de nouvelles instances d’objets.
Ici le message create crée un nouvel article en l’initialisant. Les vérifications d’usage seraient
bien sûr à effectuer ( le code de l’article n’existe t’il pas déjà au catalogue ?).
Le message sera envoyé dix fois à l’objet :B. De manière générale l’étoile placée après le
numéro désigne une itération. Nous trouverons soit une énumération de l’itération, comme ici,
une condition de continuation également ( 1.1*[not condition] :message() ). Nous trouverons
ultérieurement une itération sur tous les éléments.
Ce sont des messages itératifs, où plusieurs messages sont envoyés dans l’itération.
1 :msg() 1.1*[i :=1..10] :messageb()
:A :B
Itération
sur i de 1
à 10
1.2*[ i :=1..10] :messagec()
:C
Itération
sur le
même i
toujours de
1 à 10
Ici nous envoyons successivement un message à :B, puis un message à :C, le tout 10 fois. Il
n’y a qu’une seule boucle.
Ce sont des messages itératifs, où plusieurs itérations se suivent. Ici les boucles sont
distinctes.
1 :msg() 1.1*[i :=1..10] :messageb()
:A :B
Itération
sur i de 1
à 10
1.2*[ j :=1..10] :messagec()
:C
Itération
sur j
différent de
i
Ici nous envoyons successivement dix messages à :B, puis dix messages à :C. Il y a deux
boucles distinctes.
1 :Create()
Produit frais
1.1 :defDatePéremption(today)
La définition de la date de péremption du produit est faite par lui-même. Il sait combien de
temps il peut se conserver dans des conditions de températures normales. Donc il s’envoie le
message à lui-même.
1: lister()
Pour chaque article du catalogue, nous voulons la
description de l'intitulé de l'article.
:catalogue
Cette étoile
montre une
:Type article itération sur
tous les
éléments
Il nous reste ici à imprimer la description obtenue. Pour cela il faut envoyer un message à une
classe.
1: lister()
3*: imprimer(s)
:catalogue Systeme
:caisse :vente
Ce lien veut
dire que la
caisse connaît
la vente.
La classe caisse doit connaître la classe vente pour pouvoir lui parler:" vente , oh ma vente!
Ajoute-toi un article de ce code.".
La visibilité entre les objets n'est pas automatique. Il y a quatre manières différentes pour un
objet d'en connaître un autre.
1: desc := getdesc(code):String
:caisse :catalogue
La caisse doit connaître de manière permanente le catalogue. Elle a donc un attribut qui
référence le catalogue. Le lien montre cet attribut, car c'est la seule manière ici de connaître la
classe catalogue.
Supposons que le diagramme de séquence boîte noire mette en évidence un message de type
vérifier avec en paramètre une description d'article. Supposons également que ce soit la caisse
qui traite ce message. Nous obtenons le diagramme de collaboration suivant:
Que
Val := Vérifier(da:type art): entier celui-là
Celui-ci c'est le
:caisse même da:type art
1: p := getPrix(): entier
JC CORRE Grenoble Le Pont de Claix 06/02/2022 50
Ici la caisse ne connaît le type d'article da que temporairement. Le passage de paramètre lui
fait connaître le type d'article da à qui la caisse va envoyer un message.
Setprix(code,prix)
Récupérons
une référence
sur un objet
2: setprix(prix)
d:type art Pour pouvoir
lui envoyer
un message
Ici caisse va chercher une référence sur un type d'article, pour pouvoir envoyer un message à
ce type d'article. Ici aussi, la connaissance de l'objet est temporaire, mais elle se fait par une
variable locale.
C'est l'utilisation par un objet d'une référence globale à un objet connu de tous. Cela peut aussi
être le cas de variables globales dans le cas de certains langages. Nous comprenons bien que
ce type de visibilité sera utilisé dans de rares cas, où un objet est omniprésent pour tous les
autres objets, et sera considéré comme le contexte de vie de ces objets.
Le problème est que certaines, rares, classes ayant une instance unique doivent être connues
de nombreux objets. Il est alors conseillé d'utiliser le GOF Pattern "Singleton".
Supposons qu'une classe nécessite d'en connaître une autre ayant une instance unique ( le
magasin dans notre exemple ), et que les autres techniques de visibilité soient notoirement
malcommodes voici ce que vous pouvez faire:
La classe magasin aura une donnée membre statique instance.
A la création ( constructeur ) du magasin la donnée membre sera initialisée à this
( l'instance nouvellement créée du magasin ).
La classe magasin aura une fonction statique getInstance qui retournera l'instance du
magasin. Ainsi n'importe quelle classe pourra connaître l'objet magasin existant ( car la
méthode étant statique, elle est envoyée à la classe elle même ). Ainsi l'autre classe pourra
envoyer sa requête à l'objet magasin.
2: xxx()
3) GRASP patterns
Quand un événement est envoyé au système informatique, rien n'indique quelle classe prend
en charge l'événement et le traite en déroulant les opérations associées.
Systeme informatique
Système informatique
:caisse :vente
Qui crée
la ligne
de vente ?
Create ?
Create ?
:magasin L:lignevente
Create ?
Les qualités du logiciel qui lui permettront de vivre, d'être corrigé, d'évoluer, de grandir
dépendront complètement des choix que l'on va effectuer ici.
Les spécialistes de la conception objet, après avoir vécu quelques années de développement
anarchique, puis après avoir testé l'apport de quelques règles de construction, ont fini par
définir un certain nombre de règles pour aider le concepteur dans cette phase capitale et
difficile. Ces règles sont issues de l'expérience d'une communauté de développeurs. Ce sont
des conseils, ou des règles qui permettent de définir les responsabilités des objets. Ce sont les
modèles d'assignation des responsabilités ou GRASP Patterns ( General Responsability
Assignement Software Patterns ).
To grasp ( en anglais ) veut dire: saisir, comprendre, intégrer. Il est fondamental d'intégrer ces
modèles avant de faire de la conception objet, pour obtenir des diagrammes de classe de
conception, et des diagrammes de collaboration de qualité.
Il y a neuf grands principes pour attribuer les responsabilités aux objets, et modéliser les
interactions entre les objets. Cela permet de répondre aux questions:
Quelles méthodes dans quelles classes?
Comment interagissent les objets pour remplir leur contrat?
Quand, dans le diagramme de collaboration, un objet envoie un message à un autre objet, cela
signifie que l'objet recevant le message a la responsabilité de faire ce qui est demandé.
Les patterns sont là pour nous aider lors de la conception. C'est un couple problème solution
issu de la pratique des experts.
Nous allons voir les neuf GRASP patterns. Il y a d'autres patterns qui existent ( par exemple
GOF ( Gang Of Four ) patterns ) ceux-là sont plus dédiés à des solutions à des problèmes
particuliers ( par exemple le modèle de traitement des événements ( GOF patterns ) qui a
inspiré le modèle java de traitement des événements ).
Les GRASP patterns sont des modèles généraux de conception, et doivent être considérés par
le concepteur objet comme la base de son travail de conception.
Nous allons étudier chacun de ces patterns.
Des classes de faible cohésion font des choses diverses ( classes poubelles où sont
rangées les différentes méthodes que l'on ne sait pas classer ), ou tout simplement font trop de
choses.
Ces classes à faible cohésion sont difficiles à comprendre, à réutiliser, à maintenir.
Elles sont également fragiles car soumises aux moindres variations, elles sont donc instables.
Le programmeur doit toujours avoir ce principe de forte cohésion en tête. Il réalisera
alors des classes qui ont un rôle clairement établi, avec un contour simple et clair.
3.3) Expert
Ici nous allons établir qui rend un service. Le principe est que la responsabilité revient
à l'expert, celui qui sait car il détient l'information.
Quelle classe fournira le service getdescription ( code ) qui retourne la description d'un
article dont nous avons le code?
C'est
l'expert
C'est le catalogue qui possède les descriptions d'article, c'est lui l'expert. C'est donc lui
qui nous fournira le service getdescription.
Ce principe conduit à placer les services avec les attributs. Nous pouvons aussi garder
en tête le principe: "celui qui sait, fait".
3.4) Créateur
Quand une instance de classe doit être créée, il faut se poser la question: " Quelle
classe doit créer cet objet?".
Alors A est la classe créatrice de B. Il arrive souvent que deux classes soient de bons
candidats pour créer une instance. Alors il faut évaluer le meilleur candidat. Cela va dans
le sens du faible couplage.
Ici c'est le catalogue qui crée les descriptions d'articles.
3.5) Contrôleur
Ici nous voyons de fortes dépendances entre les objets du Système informatique et les objets
de l'interface. Si l'interface doit être modifiée, il y a de fortes chances qu'il faille également
modifier les objets du système informatique.
Notons sur cet exemple un autre problème: les classes du système informatique, ici,
connaissent les classes de l'interface utilisateur. Or, ces classes sont liées à un usage
particulier ( une application ) alors que les classes métier sont transverses à toutes les
applications. Elles ne peuvent donc pas connaître les interfaces utilisateur. Ce sont les
interfaces utilisateurs qui vont chercher les informations des objets métier, et non les objets
métier qui affichent les informations.
Les objets de l'interface utilisateur vont solliciter un objet d'interface, plutôt que de solliciter
les objets métier eux-mêmes. Cet objet s'appelle un contrôleur.
Le problème est maintenant de savoir comment nous allons choisir notre meilleur contrôleur (
il peut y en avoir plusieurs ).
L'événement entrerunarticle arrive donc sur une des quatre classes: Caisse, Magasin, Caissier
ou AchatHandler.
L'expérience montre que la troisième proposition, appelée contrôleur de rôle, est à utiliser
avec parcimonie, car elle conduit souvent à construire un objet trop complexe qui ne délègue
pas.
Les deux premières solutions, que l'on appelle contrôleurs de façade sont bien utilisées quand
il y a peu d'événements système. La quatrième proposition ( contrôleur de use case ) est à
utiliser quand il y a beaucoup d'événements à gérer dans le système. Il y aura alors autant de
contrôleurs que de use cases. Cela permet de mieux maîtriser chaque use case, tout en ne
compliquant pas notre modèle objet.
Nous avons peu d'événements à gérer. Nous prendrons donc la solution 1 ou 2. Le choix
entre ces deux propositions va se faire en appliquant les patterns précédemment établis.
3.6) Polymorphisme
Ainsi lorsque l'on sollicite un objet de cette hiérarchie, il n'est pas besoin de savoir quelle est
la nature exacte de l'objet, il suffit de lui envoyer le message adéquat ( le message
polymorphe ), et lui réagira avec son savoir faire propre.
Cela permet de faire évoluer plus facilement les logiciels. Un objet mutant ( avec un
comportement polymorphe ) est immédiatement pris en compte par les logiciels utilisant
l'objet initial. Un programme ne teste donc pas un objet pour connaître sa nature et savoir
comment l'utiliser: il lui envoie un message et l'objet sait se comporter. Cela va dans le sens
de l'éradication de l'instruction switch ( de JAVA ou de C++).
L'utilisation des différents grasp patterns nous conduit quelque fois à des impasses. Par
exemple la sauvegarde d'un objet en base de données devrait être fait par l'objet lui-même
( expert ) mais alors l'objet est lié ( couplé ) à son environnement, et doit faire appel à un
certain nombre d'outils de base de données, il devient donc peu cohérent.
La solution préconisée, dans un tel cas, est de créer de toute pièce un objet qui traite la
sauvegarde en base de données. Notre objet reste alors cohérent, réutilisable, et un nouvel
objet, dit de pure fabrication, s'occupe de la sauvegarde en base de données.
Cette solution n'est à employer que dans des cas bien particuliers, car elle conduit à
réaliser des objets bibliothèque de fonctions.
3.8) Indirection
Pour éviter le couplage, chaque objet n'a le droit de parler qu'à ses proches. Ainsi,
nous limitons les interactions entre les différents objets.
Quels sont les objets auxquels un objet à le droit de parler?
Lui-même.
Un objet paramètre de la méthode appelée.
Un objet attribut de l'objet lui-même.
Un objet élément d'une collection attribut de l'objet lui-même.
Un objet créé par la méthode.
Les autres objets sont considérés comme des inconnus auxquels, nous le savons depuis
la plus tendre enfance, il ne faut pas parler.
Prenons un exemple:
1:P:=paiement():Paiement
Total = totalvente():float :Caisse :Vente
Cette solution implique que l'objet caisse dialogue avec l'objet paiement. Hors a priori
il ne connaît pas cet objet paiement. Pour limiter le couplage entre les objets, il est
préférable d'utiliser la solution suivante:
Ici, la caisse ne sait pas comment la vente récupère le total. Des modifications de la structure
des objets vente et paiement ainsi que de leurs relations ne changent rien pour la caisse.
Nous allons faire autant de diagrammes de collaboration que nous avons fait de
contrats d'opérations. Pour chaque contrat d'opération nous allons prendre l'événement du
système comme message d'attaque de notre diagramme de collaboration, puis nous allons
créer les interactions entre les objets qui, à partir de là, permettent de remplir le service
Enregistrer
article(code) 2: [1er article] créer(date)
:Caisse 3: ajouter(da) :Vente
3.1:Ldv := créer(da)
[Link]=chercherarticle(code)
3.2: ajouter(ldv)
:Magasin Ldv:lignedev
ente Liste:lignedev
ente
3.1.1: p:=getprix()
1.1 da := chercher(code) 3.1.2: desc := getdesc()
Da:descriptio
Catalog:Descr narticle
iptionarticle
Dénombrer
( quantité) 1: dénombrer(quantité)
:Caisse :Vente
1.2:miseàjour(quantité)
1.2.1: p:=getprix()
Da:descriptio
narticle
Finirvente() 1: Finirvente()
:Caisse :Vente
Listes:lignede
vente
Payervente(s) 1:Payersomme(s)
:Caisse v:Vente
1.2:afficher(s-total)
:Afficheur
:Paiement
Le ticket :ticket
doit
connaître
la vente
pour
imprimer
Les classes ticket et vente sont étroitement couplées. Nous pouvons nous poser la question de
savoir si cette classe ticket a un intérêt. Il serait bon de faire l'impression par la vente ( l'expert
:Afficheur :imprimante
1.7*:line := desc+prix+quantité+sstotal
Payervente(s) 1:Payersomme(s)
:Caisse v:Vente
2:historiser(v) 1.2:afficher(s-total)
1.8*: imprimer(line)
1.1: créer(total)
:Magasin
:Paiement
Ventes:vent
e
Lignes:ligned
evente
1.3.1:desc:=getdesc()
1.4.1:prix:=getprix()
Da:Descriptio
narticle
Nous allons enfin construire le diagramme de classes de conception. C'est le diagramme qui
nous montre les classes qui seront développées. C'est donc l'aboutissement de ce travail
d'analyse.
Pour l'ensemble des uses cases qui composent notre cycle de développement, nous allons
réaliser le diagramme de classes de conception. Nous allons partir des diagrammes de
collaboration, qui nous donnent les classes à développer, leurs relations ainsi que les attributs
par référence. Nous complèterons ce diagramme par les attributs venant du diagramme de
classe d'analyse.
Nous allons partir uniquement du use case effectuer un achat, donc des quatre diagrammes de
collaboration du chapitre précédent. Etape par étape, nous allons construire le diagramme de
classe de conception.
1) Première étape
Nous allons référencer toutes les classes rencontrées dans les diagrammes de collaboration.
Nous allons les dessiner dans un diagramme de classes. Nous allons y ajouter les attributs
venant du diagramme de classe d'analyse, et les méthodes venant du diagramme de
collaboration.
Nous ne référençons que les classes participant à nos diagrammes de collaboration.
Les collections ne sont pas référencées en tant que telles, cela n'apporte pas de plus value.
Les messages vers les collections n'ont pas lieu d'être, les collections supportant ces
messages par défaut.
Les messages de création par défaut ne sont pas référencés, s'il n'existe pas de
constructeur par initialisation ( car alors ils existent forcément ).
Les sélecteurs et les modifieurs n'ont pas de raison de figurer dans ce schéma pour ne
pas le surcharger. En effet dans la majorité des cas, ces messages existent et sont développés à
la construction de la classe.
Caisse Vente
Date : date
Payervente(s:float) Terminé : booléen
enregistrerarticle(code : Codebarre) Total : float
dénombrer(quantité : entier) payersomme(s:float)
finirvente() Vente(date:Date)
afficher(total:float) ajouter(da:descriptionarticle)
imprimer(line:text) dénombrerquantité(q:entier)
finirvente()
Magasin Lignevente
Paiement
Nom : text Quantité : entier
Adresse : Adresse Sstotal : float
Total : float
historiser(v:vente) getdesc():Text
Paiement(total:float)
chercherarticle(code:Codebarre): Descriptionarticle getprix():Float
Lignevente(descriptionarticle da)
Descriptionarticle
Afficheur Imprimante
Description : text
Prix : réel
Code : codebarre
affichet(stt:float) imprimer(line:text)
Il faut maintenant ajouter les associations nécessaires pour montrer la visibilité par
attribut des objets. Cette visibilité par attribut va permettre de construire les attributs qui
référencent les objets que l'on doit connaître. Cette association porte une flèche de navigation
qui nous permet de connaître l'objet qui doit connaître l'autre.
Prenons trois exemples :
1:payersomme(s)
:Caisse V:Vente
Ici la caisse doit connaître en permanence la vente en cours: nous aurons une
association de type attribut.
Caisse Vente
1 traite 1..0
venteencours
Cela indique que la classe Caisse a un attribut qui référence l'objet vente en cours. Le
nom de rôle venteencours donnera, pour une génération automatique de code, le nom de
l'attribut qui référence la vente en cours.
Ajouter(da)
:Caisse
:Ventes
Ici la caisse a une visibilité de type variable locale sur la descriptionarticle ( cela serait
le même traitement si il avait une visibilité de type paramètre comme pour la Vente ). Nous
ajouterons des dépendances de type relation entre les deux classes.
Caisse Descriptionarticle
Flèche
avec des
pointillé
s
[Link]=chercherarticle(code)
:Caisse :Magasin
Ici le magasin est une instance unique pour l'application. Un certain nombre de classes
doivent connaître le magasin. Nous pouvons résoudre le problème comme au 1°. Mais, si
nous ne voulons pas multiplier les références au magasin, nous pouvons appliquer le pattern
Singleton ( Singleton pour instance unique ).
Cela revient effectivement à travailler avec une instance globale, mais fait proprement,
dans des cas rares, et répertoriés. Nous retrouverons la notation de relation entre les classes,
ici pour un accès à une variable globale.
Caisse Magasin
$boutic:Magasin
$getInstance()
(exemple en java)
public static Magasin getInstance()
{
if (boutic == null)
{
boutic = new Magasin();
}
return boutic;
}
Ainsi nous aurons une instance unique du Magasin. Cette instance peut être appelée partout en
utilisant le formalisme suivant:
(exemple en java)
Magasin monbazar = [Link]();
affichet(stt:float) imprimer(line:text)
1 1
possède
possède
0..1
Vente
1 Date : date
1 Terminé : booléen
1
réalise Total : float
Caisse payersomme(s:float)
Vente(date:Date,c:Caisse)
1 Venteencours 1 ajouter(da:descriptionarticle)
Payervente(s:float)
Se fait sur
dénombrerquantité(q:entier)
enregistrerarticle(code : Codebarre) finirvente()
dénombrer(quantité : entier)
finirvente()
afficher(total:float)
Historique *
1 1
imprimer(line:text)
effectue
0..1
enregistre
Paiement
Total : float
1
contient
Paiement(total:float)
Magasin
Nom : text
Adresse : Adresse
$boutic:Magasin
historiser(v:vente)
chercherarticle(code:Codebarre): Descriptionarticle
$getInstance():Magasin
1..*
Lignevente
1
Quantité : entier
Sstotal : float
référence
* getdesc():Text
référence getprix():Float
Lignevente(descriptionarticle da)
* catalogue
1
Descriptionarticle
Description : text
Prix : réel
Code : codebarre
Quand la vente en cours est créée , il faut lui associer la caisse sur laquelle s'effectue la
vente. Nous avons fait le choix que la vente ne connaisse que la caisse, plutôt que de
connaître chacun de ses éléments ( afficheur, imprimante,… )
La caisse joue un double rôle: celui d'interface pour le use case effectuer un achat, et
l'indirection vers les composants physiques de la caisse. Si la caisse devient trop
complexe, il vaut mieux couper la classe en deux, d'un coté l'interface du use case, et de
l'autre côté l'interface vers les composants de la caisse elle-même. Nous ne l'avons pas fait
dans le cadre de cet exercice.
Quand entre deux classes, il existe déjà une association ( ), il n'est pas utile
d'y rajouter une relation ( ). Cela n'apporte rien, sinon du bruit.
Ici, nous n'avons pas rajouté les indicateurs de visibilité ( public +, privé -,…), étant bien
entendu que les méthodes sont publiques, et les attributs sont privés. Les fonctions d'accès
aux attributs sont sous-entendues.
Les noms de rôle mis sur certaines associations donnent le nom de l'attribut dans la classe
concernée. Les associations sont unidirectionnelles et donne le sens de la visibilité. Le
diagramme nous montre que la classe Caisse a un attribut qui s'appelle venteencours qui
référence la vente en cours. De même la classe Magasin a un attribut qui s'appelle
catalogue et qui est une collection de descriptionarticle ( c'est la cardinalité qui nous
montre que dans ce cas c'est une collection ).
Les trois relations présentées sont des trois types possibles ( global, paramètre et local )
Le processus unifié est la démarche d’analyse et de conception qui s’appuie sur le langage
UML pour sa modélisation. Ce que nous avons vu jusqu’à présent, c’est une démarche
linéaire pour partir d’un besoin utilisateur jusqu’à sa réalisation. Ceci n’est pas représentatif
de la réalité des développements. Un développement d’un projet informatique va être
incrémental et itératif. Cela permet d’éviter l’effet tunnel des projets classiques ( le client perd
de vue son logiciel entre le cahier des charges et la livraison ). Ici le projet est développé en
concertation avec le client, le dialogue doit être permanent, les livraisons se font
régulièrement, permettant d’intervenir au plus tôt si il y a un écart entre le besoin du client et
le logiciel réalisé.
Nous allons donc mettre en 3 dimensions le processus que nous avons étudié.
Un lot, ou un cycle de développement, permet de livrer au client une version de logiciel. Il est
important de faire des livraisons régulières du logiciel, pour que le client garde le contrôle du
logiciel que nous lui développons. Typiquement un cycle peut durer trois semaines à deux
mois. Les exceptions viendront des gros logiciels, où une nouvelle version sort tous les ans.
Comment s’y prendre pour découper un logiciel en lot ? Nous allons lister l’ensemble des
uses cases, en les évaluant suivant deux critères : leur importance pour le client, et le risque
technique de réalisation, en notant par exemple de un à cinq chacun des critères.
Nous comprenons bien qu’il vaut mieux réaliser d’abord un module de facturation qu’un
module d’aide en ligne pour un commerçant. Il est aussi important de réaliser d’abord les
exigences à fort risque technique, afin de vérifier la faisabilité technique, et la validité de la
solution.
Nous classerons les uses cases par leur pondération ( risque + importance ). Puis nous
donnerons une logique à ce classement. Cela peut nous amener à ne vérifier qu’une faisabilité
pour un use case particulier, ou à traiter une partie des exigences d’un use case dans un
premier lot, et les autres dans un lot suivant.
Ce découpage sera validé par le client, et nous donnera les différentes livraisons qui seront
faites au client.
Notion de phases
Un lot est composé de plusieurs phases. Il y a 4 phases dans le développement d’un lot :
- Inception ou création
- Elaboration
- Construction
- Transition
Elaboration : Cette phase sert à construire l’architecture de base, et à définir la plupart des
exigences.
Transition : Cette phase sert à tester et déployer le produit chez le ou les utilisateurs.
Notion d’itération
Chacune des phases décrites, peut être effectuée en plusieurs itérations. Par exemple dans la
phase de conception, les itérations peuvent être très brèves ( de l’ordre de la demi journée,
jusqu’à deux jours ), et consiste à implémenter une classe par exemple.
Dans la phase d’élaboration, une itération pourra par exemple traiter d’un risque particulier.
Modélisation
métier
Exigences
Analyse et
Conception
Implémentation
Tests
Déploiement
Initial #1 #2 #1 #2 #n #1 #2
itérations
Nous avons vu qu’une méthode ( de type Unified Process ) qui s’appuie sur UML, permettait
d’avoir une démarche d’analyse et de conception qui nous amène de manière continue du
problème du client, vers le système qu’il désire.
Cette méthode est incrémentale et itérative. Le client voit se construire son logiciel petit à
petit, peut donc se l’approprier, se former, et mieux adapter le logiciel par rapport à son
besoin. Cette méthode permet au client de participer à l’élaboration du logiciel, et permet aux
développeurs de prendre en compte les remarques du client sans avoir à remettre en cause tout
ce qui a déjà été réalisé.
Elle permet également de se construire des bibliothèques d’objets métiers, qui permettront de
réduire les coûts des prochains logiciels à réaliser. Les informaticiens vont enfin pouvoir
capitaliser leurs compétences au sein de bibliothèques d’objets.
Il ne vous reste plus qu’à acquérir de la pratique dans cette méthode. Le développeur
commence à devenir réellement autonome sur l’ensemble de cette démarche au bout d’un an
de pratique, avec un tuteur.
Bon courage.