Modélisation UML

Introduction

L'Unified Modeling Language (UML) est un langage de modélisation permettant de représenter un programme (ou logiciel...) de façon abstraite, de telle sorte qu'il puisse être lu par tout le monde.

Par exemple un diagramme UML peut donner être utilisé pour modéliser un programme qui peut ensuite être codé dans n'importe quel langage.

Il existe plusieurs types de diagramme :

  • diagramme de classes : le plus connu, modélisation sous la forme de classes et objets.
  • diagramme de base de données : presque identique au diagramme de classes, certaines notations ont une sémantique (=sens) différent.
  • diagramme séquence : diagramme de l'exécution d'un programme
  • diagramme de déploiement : comment utiliser le programme
  • diagramme de cas d'usages : quelles sont les interactions faites avec le programme.
  • diagramme d'états-transitions : automate du programme

Cette page inclus également :

  • les patrons de conception (exemple java)
  • le model-driven development

Le logiciel StarUML est un logiciel open-source que j'utilise principalement pour faire des diagrammes UML.

Vocabulaire

Classe : fichier type, universelle, abstraite, possède des attributs, commence par une majuscule, au singulier.

Objet : souligné, on donne des valeurs aux attributs, version concrète de la classe.

Attribut : champs de la classe (nom, âge, adresse…) auquel on donnera des valeurs lorsque l’on créera un objet à partir de la classe. Il n’y a pas deux classes qui ont un attribut du même nom.

Association = trait qui relie deux classes.

Identifiant = discriminant quelque chose d’unique qui permet d’identifier un objet, il s’agit d’un attribut ou d’un groupe d’attributs que l’on souligne. Toutes les classes ont un identifiant.

Contraintes d’intégrité :

  • il s’agît de donner un type aux attributs parmi
    • String/char pour les chaines de caractères
    • int/entier/number/integer pour les entiers
    • date/dateTime pour les dates
    • float/real pour les réels
  • de faire la multiplicité
  • de respecter les propriétés (si par exemple les valeurs d’un attribut doivent être comprises dans un intervalle…).

Multiplicité

On choisit une classe, et on regarde pour la classe auquel notre classe est associé, avec combien d’objet de cette classe notre classe est en relation. (cf exemple).

On écrit la multiplicité sur/sous l’association du côté opposé à la classe que l’on a choisi.

  • 0..1 = la classe actuelle est en relation avec 0 ou 1 objet avec la classe associée.
  • 1 = la classe actuelle est en relation avec 1 objet avec la classe associée.
  • 0..* = la classe actuelle est en relation avec 0 ou un grand nombre d’objets avec la classe associée.
  • 1..* = la classe actuelle est en relation avec 1 ou un grand nombre d’objets avec la classe associée.

Par exemple : Soit dans un magasin avec des clients et des caissières. La classe Client est en relation avec 0 ou 1 caissière mais la caissière est en relation avec 0 ou un grand nombre de clients.

Création depuis un texte

1) On souligne tout ce qui est CONCRET (noms, valeurs, lieux, …)

2) On fait un tableau à deux entrées : données et informations. Les données sont celles qu’on a récupéré, information représente ce qu’est la donnée.

On regroupe les données s’il elles concernent un même rôle (par exemple client). On n’a pas à trouver des rôles pour tout le monde, toutes les infos ne sont pas forcément associées à un rôle.

3) On crée nos classes à partir de nos rôles, on souligne le discriminant (on en crée un s’il n’y en a pas dans le texte/données)...

4) On crée les associations/classes d’associations

5) On met la multiplicité

De UML vers SQL

Il existe 7 règles pour convertir un diagramme UML en code SQL

Règle 1 : Une classe = Une relation

Une Classe donne une relation, les identifiants deviennent des clés.

Règle 2 : Associations * vers *

On crée une relation avec comme nom celui de l’association.

Ses attributs sont les identifiants des deux classes, et éventuellement les attributs de la classe d’association si présente.

Son identifiant est un couple d’identifiant, qui sont les identifiant des deux classes. On met # pour clé étrangères ou on les souligne avec des tirets.

Règle 3 : Associations * vers 0.1 ou * vers 1

L’identifiant de la classe du côté de 0.1/1 va dans la classe du côté de *. Si on a une classe d’association, elle va dans la classe du côté de *.

On note qu’après en SQL, si on avait 0.1 l’attribut pourra être NULL tandis que si on avait 1, alors l’attribut ne pourra pas être NULL (=NOT NULL).

Règle 4 : Associations 1 vers 1 (même principe 0 vers 2…)

On choisit une relation et on met l’identifiant de l’autre relation dans celle qu’on a choisie (il existe donc deux façons différentes). Si on a une classe d’association, elle va dans la classe choisie.

On note qu’après en SQL, Patriarche dans Patriarche est NOT NULL.

Règle 5 : Associations réflexives

On va appliquer les règle 2,3, 4 en fonction de la multiplicité, cependant les clés étrangères (donc tous les # que l’on avait précédemment) vont prendre les nom sur l’association.

Tips : Imaginer que vous avez une association entre deux classes avec un nom de chaque côté

Règle 6 : Héritage

Règle 7 : Association n-aire

Model-driven development

Il s'agit d'une mode de développement dans lequel un logiciel est entièrement conçu (étape conception) et le développement est le reflet exact de ce qui a été conçu. (même classes, attributs, constructeurs, ... par exemple en Java).

Voici la liste des étapes selon Luc Hernandez.

  1. trouver les cas d'usages

    Il s'agit de créer une DCU (diagramme de cas d'usage) avec tous les utilisations de l'application comme lancer/fermer le programme, ...

    Attention, par exemple si une action se déclenche car l'utilisateur fait une action, alors le cas d'usage n'est pas l'action à faire mais le résultat obtenu par l'action

  2. Création du DC (basique)

    Création d'un diagramme de classes avec les potentielles classes de l'application. A ce stage, ajouter les attributs n'est pas important, il faut mettre tt ce qui vous viens en tête.

    Astuce: Vous pouvez sur StarUML colorier de différentes couleurs les classes de la vue, du model, et du controller.

  3. Diagrammes de séquence

    Il faut faire un diagramme de séquence pour chaque cas d'usage. Il s'agit de partir d'une action par exemple "exécution du programme" et de faire tous les appels de méthodes avec leurs arguments. ((l'exécution du programme appelle la méthode main de la classe X. La méthode main créé x variables, leurs types, les méthodes appelées etc... )

  4. Mise à jour du CDC

    On ajoute les nouvelles classes, les nouveaux attributs etc... découverts en faisant les diagrammes de séquences.

    Les classes sont reliées avec des flèches qui ont un sens. Elle indiquent qu'une classe contient une référence d'une autre classe et/ou inversement.

  5. Code

    Le programmeur code exactement le schéma UML.

Diagramme de classes

Une classe décrit un ensemble d’objets ayant une propriété commune. Elle contient des attributs et des opérations et garantie que chaque objet possèdera ces attributs et ces opérations.

Attributs

On écrits les attributs comme suit :

visibilité nom : type = valeur initiale

Les attributs possèdent une visibilité :

  • + corresponds à public : tout le monde
  • - correspond à privé : seulement la classe (droits avec get/set)
  • # correspond à protégé : classe et sous-classes
  • ~ correspond à package (aucun des 3 qualificatifs)

Si un attribut est calculable avec d’autres, on met un / devant sa visibilité.

On écris le cardinal (=taille) d’un attribut : [valeurMin..valeurMax].

Si le nombre de valeurs d’un attribut est limité, on écrit … type = {valeurs} (par exemple {'rouge','vert','bleu'}

Si un attribut est du type d’une autre classe présente sur le diagramme, alors on écrira l’attribut SEULEMENT sur leur association.

Opérations

Une opération est de la forme :

visibilité nom(args: type,…) : typeRetour

Une opération bien précise est précédée de « typeOpération » par exemple « constructor ».

Static

Un attribut/opération souligné est un attribut/opération de classe (static).

Associations

Deux classes peuvent être reliées par une association (trait).

Deux objets sont reliés par un lien (instance association).

La multiplicité représente combien d’objets d’une classe sont en relation avec combien d’autres d’une autre classe. On note :

  • n : exactement n éléménts
  • * : entre 0 et inf
  • n..m : entre n et m

Associations : agrégations

Association ou une classe joue un rôle plus fort que l’autre (domine l’autre ex : relation patron (1) - ouvrier (*))

Le point important d’une agrégation est que l’ouvrier existe en dehors de sa relation avec son patron sinon c’est une composition.

Associations : compositions

Il s’agît d’une agrégation plus forte où une classe (composant) n’existe pas en dehors de sa relation avec une autre (composite). (ex : les roues n’existent pas sans voiture)

La destruction du composite entraine celle du composant (classe interne)

Diagramme de classes 2

Interfaces

Une interface est un ensemble d’opérations publiques (sans implémentation). Elle est en relation avec deux types de classes :

  • classes réalisent : implémentent l’interface (Classe1)
  • classes dépendantes : utilisent interface (Classe2)

On peut également représenter une interface comme suit :

Client utilise l’interface écran tactile (=classe2) tandis que distributeur implémente les méthodes consulter et retrait de l’interface (classe1).

Une dépendance à une interface est appelé couplage fort (ici client).

On peut implémenter plusieurs interfaces.

La personne que l’on choisit pour implémenter l’interface doit être celle concernée par l’action.

Les interfaces peuvent contenir des méthodes ayant un comportement par défaut, sur le DC on les annote de « default ». C’est utile si on modifie une interface déjà implémentée.

Généralisation (notion modélisation != héritage (programmation))

Si des classes ont un/des éléments (attributs/opérations) en commun alors on peut les regrouper dans une superclasse/classe parent.

Surface est la superclasse et généralise cercle, carré…

Les attributs/méthodes de la superclasse existent dans les sous-classes mais ne sont pas représentés.

On peut substituer une superclasse par une sous-classe.

La généralisation multiple est possible en UML (pas en java, on contourne avec une/des interface(s)).

Abstraction

Une classe abstraite est une classe qui possède toutes les propriétés d’une classe normale sauf qu’elle n’est pas instanciable (car au moins une de ses méthodes peut-être abstraite (=non implémentée)).

Elle permet de regrouper une méthode/opération commune mais implémenté différemment dans ses sous-classes mais qui doit forcément être présente.

On écrit le mot clé « abstract » en italique devant le nom de la classe. Les associations sont les mêmes que celles de la généralisation.

Une opération peut être en italique pour indiquer qu’elle est abstraite ou être précédée de « abstract ».

Diagramme d'objets

Il s'agit d'un diagramme casiment identique au diagramme de classe mais qui n'est plus abstrait : toutes les classes sont instanciées.

Un objet est une instance d’une classe, ie tous les éléments ont une valeur. Les associations deviennent des liens.

  • à la place du nom de la classe, on met le nom de la variable contenant l'objet
  • si on avait une association 1..* alors on aura un objet en lien avec 0 ou plusieurs autres objets.
  • On écrit les valeur des attributs ou attribut: valeur
Diagramme de cas d'usages

Un Diagramme de cas d’usage (DCU) est un diagramme avec un système contenant des cas d'usages qui sont utilisés par des acteurs

Pour lire, créer et interpréter un DCU, il faut trouver quel est le système, les acteurs et les cas d'usages. Puis il faut identifier ce que modélisent les relations des acteurs aux cas d'usages.

Système

Ce avec quoi les acteurs interagissent (par exemple une machine à café).

Acteurs

Les entités qui interagissent avec le système. Un acteur ne représente pas un cas particulier d’interaction mais un rôle. (pas de Mr Jean mais le rôle Personne ; dans le système précédent, ce serait les clients et les adeptes du café)

Un acteur est relié à un cas d’usage par un trait (association).

On peut relier deux acteurs par une relation de généralisation (=héritage). L’acteur qui hérite peut utiliser tous les cas d’usages de l’acteur hérité.

Cas d'usages

Comment un acteur interagit avec le système. Généralement un verbe suivit d'une action (ou alors un nom de fonction/méthode). (dans le système précédent, on aurait servir café)

On peut relier deux cas d’usages par une relation

  • de généralisation : qui représente deux cas d’usages ayant des fonctionnalités similaires. (FiltrerAllergies hérite de Filtrer)
    • il s’agît d’une disjonction (un cas peut être relié par plusieurs généralisations qui symbolisent que l’on peut faire chacun de ces cas (ça ou ça ou ça))
  • d’inclusion : si un cas d’usages appelle forcément un autre au cours de son utilisation (on met « include » sur la flèche, la flèche par du cas d’usage qui appelle vers celui appelé), l’un des cas doit être à part entière.

Attention, pas de relations temporaires (par exemple si une commande implique de choisir un repas PUIS de payer, on ne lie pas commande à choisir repas puis à payer CAR c’est temporel ! On relie commander à choisir repas et payer (2 cas). )

  • d’extension : sous une condition, on appelle un cas d’usage. (on met « extends » sur la flèche, la flèche part du cas appelé vers celui qui appelle)
Diagramme séquence

Le diagramme séquence représente un exemple (donc totalement instancié) d’une utilisation de l’application.

Il est constitué de deux parties :

  • Synopsis
  • Diagramme

Synopsis

Il s’agît d’un court texte, complètement instancié (les acteurs ont des noms, les arguments des valeurs…), concentré sur 1-5 cas d’usages, décrit du point de vue de l’utilisateur qui interagit avec le système. Le texte est compréhensible par un non informaticien.

Pour interpréter un synopsis, on se demande :

  • quels est le système et quels sont les acteurs
  • quels sont les cas d’usages
  • quel est son DCU

Diagrammes séquence Système

Il s’agît d’un diagramme séquence crée en boite noire (on ne donne pas les machineries, on part du synopsis).

On va décrire quels opération sont appelées, par quel acteur, sur qui et si elle appelle d’autres opération et dans quel ordre.

Remarque : nos objets (voir plus bas) sont ordonnées des plus importants aux moins importants, du côté gauche au côté droit.

On donne un nom et une classe à nos objets. La classe peut être un acteur ou un système.

La ligne continue pointillée vers le cas est la ligne de vie de l’objet.

Les rectangles représentent le temps d’exécution d’une opération

Un objet appelle une opération sur un autre objet avec une flèche noire. Elle peut appeler d’autres opérations et optionnellement renvoyer quelque chose.

Lorsqu’une opération renvoi quelque chose (void, String,…) on parle de message synchrone = appel = bloquant. Si l’opération lance un nouveau thread ou ne renvoi rien, on parle de message asynchrone = message.

Le temps se lit de haut en bas (on numérote) et pour chaque appel d’opération, on distingue le moment où on envoi l’appel, de celui où il est reçu. ( ! On n’a pas retour avant appel…)

Note : Les usages des diagrammes séquence doivent être présents dans les DCU lorsqu’il s’agît d’interactions avec l’extérieur. Les messages sont des associations décrites dans les autres diagrammes.

Un message de A vers B doit exister dans la classe B et les arguments doivent correspondre.

Diagrammes séquence Détaillé

On éclate le DSS en objets, on est maintenant en boite blanche, et on regarde.

On ajoute les création d’objets et on donne des arguments aux méthodes.

On écris la documentation à côté :

  • qui appelle la méthode
  • quel sont des arguments
  • quel est son type de retour

Pour créer un objet, le message envoyé est « create » et la référence de l’objet crée est renvoyé.

S’il est détruit, alors son cycle de vie finie avec une croix. Si on le détruit, alors le message envoyé est « destroy ». (une croix)

Diagramme séquence : cadres d'interactions

Les cadres d’interactions permettent d’ajouter des algorithmes aux diagrammes séquences.

le cadre alt (=alternatives) et opt (= optionnel)

Le cadre d’intéraction alt et une structure if() else if else avec elseif et else facultatifs. On met une [garde] qui correspond à la condition, on exécute les appels du bloc si elle est validée.

Java : If (condition1) message1() else message2()

Le cadre opt est un cadre alt mais seulement un if(condition) then code.

le cadre loop

Une simple boucle while, tant que la condition est valide.

les cadres sd (sequence diagram) et ref (reference)

Sq est un cadre dans lequel on met un diagramme de séquence, comme si on le met dans une variable. On peut diviser notre diagramme de séquence en sous diagramme et ref permet de les appeler.

les cadre par (parralèle), seq (séquence), critical

par exécute simultanément tous ses blocs, et seq les fait un par un.

critical indique une action qui doit forcément marcher si on veut continuer

le cadre break (interruption)

Il s’agît d’un fragment qui s’il est exécuté (garde), alors met fin à tout appel de méthode et à l’exécution du bloc.

Patrons de conception

Les patrons de conceptions sont des méthodes que d'autres programmeurs ont pensés pour résoudre certains problèmes

Patrons de construction = manières de créer des objets

  • Factory : délègue construction, passe par une interface (Interface i = new Object())
  • AbstractFactory : délègue construction, on cache type (Interface i = Interface.getObject())
  • Singleton : une seule instance (garde instance static, getInstance)

Patrons de structuration = manières structurer le programme

  • Adaptor : Le patron Adaptor permet de faire intéragir l’utilisateur avec une méthode, qui va exécuter d’autres méthodes en fonction d’où elle doit aller chercher l’information.
  • Façade : Api simplifiée, une méthode peut avoir plusieurs comportements
  • Composite : classe abstraite implémentée par parents et enfants

Patrons de comportement = façons d’interagir entres objets

  • Iterator : Le patron Iterator (+Iterable) permet d’itérer un objet sans connaitre son contenu. (parcours de façon générique, simultanée sans duplication).
  • Observable : Le patron Observable (+Observer) associe à un observer des objets observables qu’il peut actualiser s’il a changé (utile répercuter M->V).
  • Décorateur : pointeur sur un objet, rédéfini de ses méthodes
  • Memento : charge et sauvegarde objet, ou utiliser fichiers xml, json, bd…
  • NullObjet : classe dont les méthodes ne font rien

Patrons d’architecture

  • MVC : Le Modèle MVC (modèle vue contrôleur)
  • DOA : Le DAO (data access objet).
Diagramme états-transition

Le but est de représenter TOUS les comportements que peuvent prendre les objets d’une classe.

On représente tous les états possibles de l’application puis les transitions ie comment on passe d’un état à un autre et enfin s’il existe des conditions pour changer d’état.

États

On commence par identifier les états possibles de notre objet tout en regroupant les états aux comportements similaires. (pas A et B)

On peut définir des actions à effectuer dès que l’on rentre/sort/… d’un état pour éviter de surcharger les branches.

État spéciaux

L’état initial est un état transitoire qui indique où on commence. On n’y reste pas, on va directement dans un nouvel état. (ex : Attente)

L’état final de notre objet, il peut ne pas en avoir si notre objet n’est jamais détruit.

aazd

Transitions

On passe d’un état à un autre avec une transition. On peut écrire dessus l’évènement qui nous fait changer d’état.

On peut également ajouter une garde à notre transition contenant une condition pour transiter. Forme : [condition]

On peut également ajouter une action à notre transition contenant du code à exécuter. Forme : /action

Branchement

« sinon », on crée un branchement qui va évaluer les conditions de toutes les branches reliées.

Si une condition échoue, alors l’automate vérifie les autres branches ou prends celle avec [sinon].

Une barre de synchro représente le fait que l’on doit finir toutes les flèches qui lui viennent dessus avant de continuer.