Vous êtes sur la page 1sur 28

Claude Belleil

Université de Nantes

Le langage UML 2.0


OCL (Object Constraint Language)

1 Préambule
Ce document présente et définit les caractéristiques principales du Langage OCL (Object Constraint
Language), en s’inspirant du document officiel de l’OMG1. OCL est un langage formel utilisé pour exprimer
des contraintes dans un modèle objet.
Le langage OCL a été utilisé dans le document de présentation de la sémantique du langage UML « UML
semantics »2 pour spécifier les règles de bonne formation du métamodèle UML. Chaque règle de bonne
formation dans les sections concernant les modèles statiques des documents de spécification UML contient
une expression OCL qui est un invariant de la classe concernée.
La grammaire OCL est précisée à la fin de ce document. Un analyseur syntaxique3 (OCL parser) construit à
partir de cette grammaire a correctement traité toutes les contraintes correspondant au document « UML
semantics ». C’est un processus qui a contribué à améliorer l’exactitude des spécifications pour OCL et
UML.

1.1 Pourquoi OCL?


En modélisation orientée objet, un modèle graphique comme la représentation d’une classe n’est parfois pas
suffisant à exprimer la réalité, dans le cadre d’une spécification précise et non ambiguë.
Il est souvent nécessaire de décrire des contraintes supplémentaires sur les objets du modèle. De telles
contraintes sont souvent rédigées en langage naturel. La pratique a montré que cela aboutissait souvent à
des ambiguïtés.
Afin d’écrire des contraintes sans ambiguïtés, des langages également appelés « langages formels » ont été
développés. De tels langages présentent un inconvénient majeur. Ils ne peuvent être utilisés que par des
personnes ayant une bonne pratique de la notation mathématique, ce qui constitue souvent un handicap
dans les domaines de la gestion ou de la modélisation des systèmes.

OCL a été développé pour palier cette difficulté. C’est un langage formel qui reste facile à lire et à écrire. Il a
été développé comme un langage de modélisation de gestion dans le département IBM de l’assurance et
prend ses racines dans la méthode Syntropy4.
1
http://www.omg.org/
2
http://www-306.ibm.com/software/rational/uml/resources/documentation.html
3
http://www-306.ibm.com/software/awdtools/library/standards/ocl-download.html
4
http://www.sciences.univ-nantes.fr/info/perso/permanents/habrias/lexique.html
_____________________________________________________________________________ 1
Le Langage UML 2.0 Claude Belleil Université de Nantes
OCL est un langage d’expressions. De plus, une expression OCL est garantie comme étant sans effet de
bord5. Elle ne peut pas provoquer de changements dans le modèle. Cela signifie que l’état du système ne
sera jamais modifié du fait de l’évaluation d’une expression OCL. En revanche, une expression OCL peut
être utilisée pour spécifier un changement d’état, par exemple dans une post-condition comme nous le
verrons par la suite. Les valeurs pour tous les objets, incluant également tous les liens ne seront pas pour
autant changées.

A chaque fois qu’une expression OCL est évaluée, elle délivre simplement une valeur. OCL n’est pas un
langage de programmation. Ainsi, il n’est pas possible d’écrire une logique de programme ou un contrôle de
flux en OCL. On ne peut pas appeler des processus ou activer des opérations au sens algorithmique. Parce
qu’OCL est avant tout un langage de modélisation, il ne contient pas d’instructions qui soient directement
exécutables.

Par ailleurs, OCL est un langage typé. Chaque expression OCL possède un type. Par conséquent, dans
une expression OCL correcte, les types utilisés doivent être conformes (on ne peut pas comparer un entier
avec une chaîne de caractères).

En OCL, les types sont ceux répertoriés dans le langage UML. En tant que langage de modélisation, toutes
les questions d’implémentation sont en dehors du champ d’application et ne peuvent pas être exprimées
dans ce langage.

Chaque expression OCL est conceptuellement élémentaire. L’état des objets du système ne peut pas être
changé pendant son évaluation.

1.2 Comment utiliser OCL


OCL peut être utilisé avec des objectifs différents:

• Pour spécifier des invariants sur des classes ou des types dans un modèle de classes.
• Pour spécifier un type invariant pour un stéréotype.
• Pour décrire des pré et post conditions sur des opérations et des méthodes.
• Pour décrire des gardes
• Comme langage de navigation dans un diagramme
• Pour spécifier des contraintes sur des opérations.

Dans le document consacré à la sémantique d’UML, OCL est utilisé dans les règles de bonne formation en
tant qu’invariant sur les méta-classes. A plusieurs endroits, le langage est également utilisé pour définir des
opérations additionnelles utilisées dans les règles de bonne formation.

Depuis la version 1.4 d’UML, ces opérations additionnelles peuvent être formellement définies en utilisant
les contraintes de définition et les expressions d’affectation.

2 Introduction
2.1 Légende
Le texte écrit en police de caractère courier tel que ci-dessous est une expression OCL:

5
Modification indirecte de la valeur d' une variable. C'
est une traduction mot à mot de l' expression anglaise
« side effect » qui signifie en bon français « effet secondaire ». C' est ce qui se passe « au bord » d' un
programme, et qui n' arriverait pas si le programme s' exécutait tout seul dans le vide. Mais le programme
s'exécute au milieu d' un système dans lequel, en général, d' autres applications sont en train de s'
exécuter

_____________________________________________________________________________ 2
Le Langage UML 2.0 Claude Belleil Université de Nantes
'This is an OCL expression'

Le mot réservé context introduit le contexte d’une expression. Les mots réservés inv, pre et post
signalent respectivement les stéréotypes invariant, précondition et postcondition de la contrainte.
L’expression OCL suivante commence après les deux points :

context TypeName inv:


'this is an OCL expression with stereotype <<invariant>> in the
context of TypeName' = 'another string'

Dans les expressions OCL de ce document, les mots réservés sont écrits en caractères gras. Les caractères
gras n’ont pas de signification formelle mais sont utilisés pour rendre les expressions plus lisibles. Les
expressions OCL n’utilisent que les caractères ASCII.

2.2 Diagramme de classes

Figure 1 : Diagramme de classe "exemple"

Le diagramme de classes ci-dessous est utilisé pour les exemples.

_____________________________________________________________________________ 3
Le Langage UML 2.0 Claude Belleil Université de Nantes
3 Lien avec le méta modèle UML
3.1 Self
Chaque expression OCL est écrite dans le contexte d’une instance d’un type spécifique. Dans une
expression OCL, le nom self est utilisé pour faire référence à l’instance de contexte. Par exemple, si le
contexte est Company, alors self fait référence à une instance de Company6.

3.2 Spécification du contexte UML


Dans un modèle UML, le contexte d’une expression OCL peut être spécifié au travers d’une déclaration de
contexte au début d’une expression OCL.
Si la contrainte est indiquée dans un diagramme avec son propre stéréotype et les lignes de pointillés la
reliant à son élément de contexte, il n’est pas nécessaire d’avoir une déclaration explicite de contexte dans
le test de la contrainte. La déclaration de contexte est optionnelle.

3.3 Les invariants


Une expression OCL peut être un élément d’un invariant qui est une contrainte stéréotypée avec «invariant».
Quand l’invariant est associé à un classificateur, celui-ci est référencé en tant que « type ». L’expression est
alors un invariant du type et doit être vrai pour les instances ce type à n’importe quel moment.

Par exemple, dans le contexte du type Company, l’expression suivante spécifie comme un invariant que le
nombre d’employés doit toujours être supérieur à 50

self.numberOfEmployees > 50

Ici, self est une instance du type Company.

On peut voir self comme un objet à partir duquel on construit l’expression.

Le type de l’instance de contexte d’une expression OCL qui est un élément d’un invariant est écrit avec le
mot réservé context suivi par le nom du type. L’étiquette inv : declare la contrainte comme étant une
contrainte invariante :

context Company inv:


self.numberOfEmployees > 50

Dans de nombreux cas, self peut être omis, parce que le contexte est clair comme dans les exemples ci-
dessous. Comme alternative à l’utilisation de self, un nom différent peut être défini, jouant ainsi le rôle de
self.

context c:Company inv:


c.numberOfEmployees > 50

Cet exemple est identique à l’exemple précédent qui utilisait self.

De façon optionnelle, le nom de la contrainte peut être écrit après le mot réservé inv permettant à la
contrainte d’être référencée par un nom. Dans l’exemple suivant le nom de la contrainte est

6
Donc à un objet
_____________________________________________________________________________ 4
Le Langage UML 2.0 Claude Belleil Université de Nantes
enoughEmployees. Dans le méta modèle UML, ce nom est un attribut de la métaclasse Constraint
qui est héritée de ModelElement.

context c : Company inv enoughEmployees:


c.numberOfEmployees > 50

3.4 Pré et post conditions


Une expression OCL peut être un élément d’une pré-condition ou d’une post-condition correspondant aux
stéréotypes de contraintes associés à une opération ou à une méthode. Alors, l’instance de contexte self
est une instance du type qui possède l’opération ou la méthode comme caractéristique. En OCL, la
déclaration de contexte utilise le mot clé context, suivi du type et de la déclaration d’opération.
Les étiquettes pre : et post : déclarent les contraintes comme étant respectivement une contrainte de
pré condition ou une contrainte de post condition.

context Typename::operationName(param1 : Type1, ... ): ReturnType


pre : param1 > ...

post: result = ...

Le nom self peut être utilisé dans l’expression faisant référence à l’objet sur lequel l’opération a été
appelée, et le nom du résultat est le nom de l’objet retourné, s’il y en a un. Les noms des paramètres
(param1,… ) peuvent aussi être utilisés dans une expression OCL. Dans le diagramme de classes de
l’exemple, nous pouvons écrire :

context Person::income(d : Date) : Integer


post: result = 5000

De façon optionnelle, le nom d’une pré ou post condition peut être écrit après les mots réservés pre ou
post, permettant à la contrainte d’être référencée par son nom. Dans l’exemple suivant, le nom de la pré
condition est parameterOk et le nom de la post condition resultOk. Dans le méta modèle UML, ces
noms sont des attributs de la métaclasse Constraint qui hérite de ModelElement

context Typename::operationName(param1 : Type1, ... ): ReturnType


pre parameterOk: param1 > ...
post resultOk: result = ...

3.5 Le contexte Package


La déclaration de contexte package est assez précise quand le package dans lequel le classificateur
apparaît est évident dans l’environnement. Pour spécifier explicitement dans quel package les contraintes
invariant, pré ou post apparaissent, celles-ci peuvent être encadrées par les instructions package
et endpackage. Les instructions de package ont la syntaxe suivante :

package Package::SubPackage
context X inv:
... some invariant ...
context X::operationName(..)
pre: ... some precondition ...

_____________________________________________________________________________ 5
Le Langage UML 2.0 Claude Belleil Université de Nantes
endpackage

Un fichier ou un flux OCL peuvent contenir n’importe quel nombre d’instructions de package, permettant
ainsi à tous les invariants, pré conditions et post conditions d’être écrits à la suite les uns des autres et
rangés dans un fichier. Ce fichier peut coexister avec un modèle UML en tant qu’entité séparée.

3.6 Expressions générales


Toute expression OCL peut être utilisée comme valeur pour un attribut de la classe UML Expression ou
pour un de ses sous types. Dans ce cas, les documents sémantiques décrivent la signification de
l’expression.

4 Valeurs élémentaires et types


En OCL, le nombre de types élémentaires est prédéfini et disponible à tout moment pour le modélisateur.
Ces types de valeurs prédéfinis sont indépendants de tout modèle objet et font partie de la définition d’OCL.
La valeur la plus élémentaire en OCL est la valeur d’un des types de base. Les quelques types élémentaires
utilisés dans les exemples de ce document sont les suivants :

type valeurs
Boolean true, false
Integer 1, 2, 34, 26524, ...
Real 1.5, 3.14, ...
String 'To be or not to be...'

OCL définit un certain nombre d’opérations sur les types prédéfinis. Le tableau suivant donne quelques
exemples d’opérations et de types prédéfinis. La liste complète des opérations est donnée en section 6.8 du
document7 de l’OMG (Object Constraint Language Specification)

type operations
Integer *, +, -, /, abs()
Real *, +, -, /, floor()
Boolean and, or, xor, not, implies, if-then-else
String toUpper(), concat()

Collection, Set, Bag et Sequence sont également des types élémentaires. Leurs spécificités seront
décrites dans les sections suivantes.

4.1 Types provenant du modèle UML


Chaque expression OCL est écrite dans le contexte d’un modèle UML, d’un certain nombre de types/classes
de leurs caractéristiques et associations et de leurs généralisations. Tous les types/classes provenant d’un
modèle UML sont typés en OCL.

4.2 Types énumération


Les énumérations correspondent à des types de données UML. Elles possèdent un nom, comme n’importe
quel autre classificateur.

7
Voir le document : OCL_Annexe.pdf
_____________________________________________________________________________ 6
Le Langage UML 2.0 Claude Belleil Université de Nantes
Une énumération définit un ensemble de littéraux qui correspondent aux valeurs possibles de l’énumération.
Dans le cadre du langage OCL, on peut faire référence à la valeur d’une énumération. Quand on a un type
de données nommé Sex avec les valeurs « female » ou « male », ils peuvent être utilisés de la
façon suivante :

context Person inv:


sex = Sex::male

4.3 L’expression Let et les contraintes de définition

Parfois une sous-expression est utilisée plusieurs fois dans une contrainte. L’expression let permet de
définir un attribut ou une opération qui peut être utilisé dans une contrainte.

context Person inv:


let income : Integer = self.job.salary->sum()
let hasTitle(t : String) : Boolean =
self.job->exists(title = t) in
if isUnemployed then
self.income < 100
else
self.income >= 100 and self.hasTitle(`manager')
endif

Une expression let peut être incluse dans un invariant, une pré ou post condition. Alors, elle est
uniquement connue à l’intérieur de cette contrainte spécifique. Pour pouvoir réutiliser les opérations et/ou
variables let, on peut utiliser une contrainte avec le stéréotype définition def: dans laquelle les opérations
et/ou variables let sont définies.
Cette définition de contrainte doit être attachée à un classificateur et ne peut contenir que les définitions
let. Toutes les variables et opérations définies dans la contrainte de définition def : sont connues dans
le même contexte où les propriétés du classificateur peuvent être utilisées. Par essence, de telles variables
et/ou opérations sont des pseudo attributs ou des pseudo opérations du classificateur. Elles sont utilisées
dans une expression OCL exactement de la même façon qu’un attribut ou une opération. La contrainte de
définition utilise le mot réservé def : comme il est montré ci-dessous :

context Person def:


let income : Integer = self.job.salary->sum()
let hasTitle(t : String) : Boolean =
self.job->exists(title = t)

Les noms des attributs et des opérations dans une expression let ne doivent pas entrer en conflit avec des
noms d’attributs de terminaisons d’association (rôle) ou d’opérations déjà définis dans le classificateur. De
plus, les noms de toutes les variables et opérations en relation avec le classificateur doivent être uniques.

4.4 Conformité de types


OCL est un langage typé et les valeurs élémentaires de types sont organisées dans une hiérarchie de types.
Cette hiérarchie détermine la conformité des différents types les uns par rapport aux autres. Par exemple on
ne peut pas comparer un Integer avec un Boolean ou un String. Une expression OCL dans laquelle
tous les types sont en conformité est une expression valide. Une expression OCL dans laquelle les types ne
sont pas en conformité est une expression invalide. Elle contient une erreur de conformité de type.

Un type type1 est en conformité avec un type type2 quand une instance de type1 peut être substituée à
chaque endroit où une instance de type2 est attendue. Dans les diagrammes de classes, les règles de
conformité de type sont simples :

_____________________________________________________________________________ 7
Le Langage UML 2.0 Claude Belleil Université de Nantes
• Chaque type et conforme à son supertype
• La conformité de type est transitive. Si type1 est conforme à type2 et type2 conforme à type3,
alors type1 est conforme à type3

La conséquence de cette règle est qu’un type est conforme à son supertype et à tous les supertype au
dessus.

Les règles de conformité de type pour les valeurs de type sont les suivantes:

Type conforme à.. / est un sous type de..


Set Collection
Sequence Collection
Bag Collection
Integer Real

La relation de conformité entre les types Collection est seulement conservée si il y a des collections de types
qui sont conformes l’un à l’autre. Voir le paragraphe 5.13 pour les règles complètes de conformité pour les
collections.

Dans la table suivante quelques exemples d’expressions valides et non valides sont présentées :

OCL expression valid? error


1 + 2 * 34 yes
1 + 'motorcycle' no type Integer does not conform to type String

23 * false no type Integer does not conform to Boolean


12 + 13.5 yes

4.5 Re typage ou consolidation


Dans certaines circonstances, il est souhaitable d’utiliser une propriété d’un objet qui est définie sur un sous
type du type courant connu de l’objet. Parce que la propriété n’est pas définie sur le type courant connu, ceci
a pour résultat une erreur de conformité de type.

Quand il est certain que le type actuel de l’objet est un sous type, l’objet peut être retypé en utilisant
l’opération oclAsType(OclType). Cette opération a pour résultat le même objet, mais le type connu est
l’argument OclType.

Quand il y a un objet object de type Type1 et que Type2 est un autre type, il est permis d’écrire:

object.oclAsType(Type2) --- évalue l’objet avec le type Type2

Un objet peut seulement être retypé dans un de ses sous-types, par conséquent, dans l’exemple précédent
Type2 doit être un sous type de Type1.

Si le type actuel de l’objet n’est pas égal au type pour lequel il est retypé, l’expression est indéfinie (voir
4.10)

4.6 Règles de précédence


L’ordre de priorité pour les opérations en OCL est le suivant:

_____________________________________________________________________________ 8
Le Langage UML 2.0 Claude Belleil Université de Nantes
. @pre
. dot and arrow operations: `.' and `->'
. unary `not' and unary minus `-'
. `*' and `/'
. `+' and binary `-'
. `if-then-else-endif'
. `<', `>', `<=', `>='
. `=', `<>'
. `and', `or' and `xor'
. `implies'

Des parenthèses peuvent être utilisées pour changer l’ordre des priorités.

4.7 Utilisation des opérateurs infixes8


L’utilisation des opérateurs infixes est autorisée en OCL. Les opérateurs suivants sont utilisés comme
opérateurs infixes:

‘+’, ‘-', ‘*', ‘/', ‘<‘, ‘>', ‘<>' ‘<=' ‘>=', ‘and', ‘or', et ‘xor'

L’expression :

a + b

est conceptuellement équivalente à l’expression:

a.+(b)

qui appelle l’opération + sur a avec b comme paramètre de l’opération.

Les opérateurs infixes définis pour un type doivent avoir exactement un paramètre. Pour les opérateur
infixes suivants :

‘<‘, ‘>', ‘<>' ‘<=' ‘>=', ‘and', ‘or', et ‘xor'

Le type retourné doit être boolean.

4.8 Les commentaires


En OCL, les commentaires sont placés après deux tirets. Tout ce qui est placé après deux tirets jusqu’à et y
compris la fin de ligne est considéré comme un commentaire.

Par exemple:

-- ceci est un commentaire

8
Les expressions arithmétiques sont habituellement écrites de manière infixe, c' est à dire l'
opérateur entre
ses deux opérandes (ou avant si c' est un opérateur unaire mais c'
est pas le problème). On trouve aussi une
notation postfixée, que l'
on appelle également notation polonaise car introduite par le polonais Lukasiewicz :
l'
opérateur est placé après ses opérandes.

_____________________________________________________________________________ 9
Le Langage UML 2.0 Claude Belleil Université de Nantes
4.9 Valeurs indéfinies
A chaque fois qu’une expression OCL est évaluée, il existe une possibilité qu’une ou plusieurs requêtes
dans l’expression soient indéfinies. Si c’est le cas, alors l’expression complète sera indéfinie. Il existe deux
exceptions à cela concernant les opérateurs booléens :

• True OR n’importe quoi est égal à True


• False AND n’importe quoi est égal à False

Les deux règles ci-dessus sont valides quelque soit l’ordre des arguments et si la valeur des autres sous
expressions est connue ou non.

5 Objets et propriétés
Les expressions OCL peuvent se référer à des types, des classes, des interfaces, des associations
(agissant comme des types) et des types de données. Egalement, tous les attributs, terminaisons
d’associations (rôles), méthodes et opérations sans effets de bord qui sont définis sur ces types, classes, …
etc peuvent être utilisés.

Dans un modèle de classes, une opération ou une méthode est définie sans effet de bord si l’attribut
isQuery de l’opération est vrai. Dans la suite de ce document, nous ferons référence aux attributs,
terminaisons d’associations, méthodes et opérations sans effet de bord comme étant des propriétés. Par
conséquent, une propriété est un des éléments suivants :

• Un Attribut
• Une terminaison d’association (rôle)
• Une Association avec isQuery égal à vrai
• Une Méthode avec isQuery égal à vrai

5.1 Les propriétés


La valeur d’une propriété sur un objet qui est définie dans un diagramme de classe est spécifiée par un
point, suivi par le nom de la propriété:

context AType inv:


self.property

Si self est une référence à un objet, alors self.property est la valeur de la propriété property sur
self.

5.2 Propriétés: attributs


Par exemple, l’age d’une personne Person est noté de la façon suivante:

context Person inv:


self.age > 0

La valeur de cette expression est la valeur de l’attribut age sur la personne self.Le type de cette
expression est le type de l’attribut age, qui est du type élémentaire Integer.

_____________________________________________________________________________ 10
Le Langage UML 2.0 Claude Belleil Université de Nantes
Avec les attributs et les opérations définis sur les valeurs de type élémentaire, nous pouvons exprimer des
calculs sur le modèle de classe. Par exemple, une règle de gestion peut être « l’âge d’une personne est
toujours supérieur ou égal à zéro ». Ceci peut être déclaré comme un invariant.

5.3 Propriétés: Opérations


Les opérations peuvent avoir des paramètres. Par exemple, dans le diagramme de classes présenté plus
haut, un objet Person a un revenu exprimé comme une fonction de date. Cette opération peut-être
représentée comme ci-dessous pour une Personne aPersonn et une date aDate:

aPerson.income(aDate)

L’opération peut elle-même être définie par une contrainte de postcondition. C’est une contrainte qui est
stéréotypée comme postcondition. L’objet qui est retourné par l’opération peut être référencé par
result. La forme est la suivante :

context Person::income (d: Date) : Integer


post: result = age * 10009

La partie droite de cette définition peut faire référence à l’opération qui a été définie, c'
est-à-dire que la
définition peut être récursive, aussi longtemps que la récursion est correctement définie. Le type du résultat
est le type retourné par l’opération, c'
est-à-dire un entier dans l’exemple ci-dessus.

Pour faire référence à une opération ou une méthode qui ne prennent pas de paramètres, des parenthèses
avec une liste vide d’argument sont utilisés :

context Company inv:


self.stockPrice() > 0

5.4 Propriétés: Extrémités (rôles) d’associations et navigation


En partant d’un objet spécifique, dans un diagramme de classes on peut parcourir une association pour faire
référence aux autres objets et à leurs propriétés. Pour faire cela, on parcourt l’association en utilisant la
partie terminale de l’association du côté opposé :

object.rolename

La valeur de cette expression est constituée de l’ensemble des objets de l’autre côté du nom de rôle de
l’association. Si la cardinalité de la terminaison de l’association a un maximum égal à 1 (0..1 ou 1), alors la
valeur de cette expression est un objet. Dans le diagramme de classes de l’exemple, quand nous
commençons la navigation dans le contexte de Company, c' est-à-dire, une instance de Company, on peut
écrire :

context Company
inv: self.manager.isUnemployed = false
inv: self.employee->notEmpty()

Dans le premier invariant, self.manager est une personne, parce que la cardinalité de l’association est 1.
L’évaluation de la seconde expression donnera un résultat de type ensemble de personnes. Par défaut, la
navigation fournit un résultat du type Set.

9
Exemple bizarre, repris du document officiel !
_____________________________________________________________________________ 11
Le Langage UML 2.0 Claude Belleil Université de Nantes
Les collections tels que Set, Bag et Sequence sont des types prédéfinis en OCL. Il existe un grand nombre
d’opérations prédéfinies les concernant. Une propriété de la collection peut être adressée en utilisant une
flèche ‘->’ suivie par le nom de la propriété.

L’exemple suivant se place dans le contexte d’une personne :

context Person inv:


self.employer->size() < 3

Ceci applique la propriété size (dimension) sur l’ensemble (Set) self.employer qui fournit comme
résultat le nombre d’employés de Person self.

context Person inv:


self.employer->isEmpty()

Ceci applique la propriété isEmpty sur l’ensemble self.employer. Cela est évalué à Vrai si l’ensemble
des employés est vide et à faux dans l’autre cas.

5.4.1 Absence de Nom de rôle

A chaque fois qu’un nom de rôle est omis sur une des extrémités d’une association, le nom du type de
l’extrémité de l’association, commençant par une lettre minuscule est utilisé en tant que nom de rôle.
Si le résultat est ambigu, le nom de rôle est obligatoire. C’est le cas avec les noms de rôle absents sur les
associations réflexives. Si le nom de rôle est ambigu, il ne peut pas être utilisé en OCL.

5.4.2 Navigation sur des associations avec des cardinalités Zéro ou un

Parce que la cardinalité du rôle manager est égale à un, self.manager est un objet de type Person.
Un tel objet unique peut être utilisé comme un ensemble. Alors, il se comporte comme un ensemble ne
contenant qu’un seul objet. L’usage en tant que set est fait au travers de la flèche, suivi de la propriété de
l’ensemble. Ceci est montré dans l’exemple suivant :

context Company inv:


self.manager->size() = 1

self.manager est utilisé en tant qu’ensemble (Set) parce que la flèche est utilisée pour accéder à la
propriété size sur l’ensemble. Le résultat renvoyé est 1

L’exemple suivant illustre comment une propriété de collection peut être utilisée.

context Company inv:


self.manager->foo10

self.manager est utilisé en tant qu’ensemble (Set) parce que la flèche est utilisée pour accéder à la
propriété foo sur l’ensemble. Cette expression est incorrecte puisque foo n’est pas une propriété définie de
l’ensemble.

context Company inv:


self.manager.age> 40

self.manager est utilisé en tant que Personne parce que le point est utilisé pour accéder à la propriété
age de Person

10
Jargon américain attribuant un nom à un programme et signifiant « machin », « truc », souvent associé à
bar
_____________________________________________________________________________ 12
Le Langage UML 2.0 Claude Belleil Université de Nantes
Dans le cas d’une cardinalité optionnelle (0..1), ceci est spécialement utilisé pour contrôler si il y a un objet
ou non quand on parcourt l’association. Dans cet exemple nous pouvons écrire :

context Person inv:


self.wife->notEmpty() implies self.wife.sex = Sex::female

5.4.3 Propriétés combinées

Les propriétés peuvent être combinées pour faire des expressions plus complexes. Une importante règle est
qu’une expression OCL est toujours évaluée pour un objet d’un type spécifique. Sur ce résultat, on peut
toujours appliquer une autre propriété. Ainsi, chaque expression OCL peut être lue et évaluée de la gauche
vers la droite.

Voici quelques invariants qui utilisent des propriétés combinées à partir de l’exemple du diagramme de
classe du début de ce document.

Les gens mariés sont agés de plus de 18 ans

context Person inv:


self.wife->notEmpty() implies self.wife.age >= 18 and
self.husband->notEmpty() implies self.husband.age >= 18

Une entreprise a au moins 50 employés

context Company inv:


self.employee->size() >= 50

5.5 Navigation et types d’associations


Pour spécifier la navigation sur les classes associations (Job et marriage dans l’exemple), OCL utilise un
point (.) et le nom de la classe association qui commence par une minuscule :

context Person inv:


self.job

La sous expression self.job est évaluée comme l’ensemble de tous les emplois qu’une personne a avec
les entreprises qui sont son employeur. Dans le cas d’une classe association, il n’y a pas de nom de rôle
explicite dans le diagramme de classes. Le nom job utilisé dans cette navigation est le nom de la classe
association commençant par une minuscule, de façon similaire à celle décrite précédemment dans la section
«Absence de Nom de rôle ».

Figure 2 : navigation récursive sur une classe association


_____________________________________________________________________________ 13
Le Langage UML 2.0 Claude Belleil Université de Nantes
Quand on parcourt un modèle sur une classe association telle que EmployeeRanking11 , il y a deux
possibilités qui dépendent de la direction du parcours. Par exemple, dans l’exemple ci-dessus on peut
parcourir vers le rôle employees ou vers le rôle bosses. En n’utilisant que le nom de la classe association,
ces deux options ne peuvent pas être différenciées. Pour réaliser cette distinction, le nom du rôle vers lequel
on veut effectuer le parcours doit être ajouté au nom de la classe association en le plaçant entre crochets.

Dans l’expression :

context Person inv:


self.employeeRanking[bosses]->sum() > 0

self.employeeRanking[bosses] évalue l’ensemble employeeRanking appartenant à la collection


bosses.

Et dans l’expression :

context Person inv:


self.employeeRanking[employees]->sum() > 0

self.employeeRanking[employees] évalue l’ensemble employeeRanking appartenant à la collection


employees.

5.6 Navigation à partir des classes associations


On peut naviguer à partir d’une classe association vers les objets qui participent à cette association. Ceci est
réalisé en utilisant la notation par le point et les noms de rôles sur les extrémités des associations.

context Job
inv: self.employer.numberOfEmployees >= 1
inv: self.employee.age > 21

La navigation à partir d’une classe association vers un des objets de l’association délivrera toujours
exactement un objet. C’est le résultat de la définition de la classe association. Par conséquent, le résultat de
cette navigation est exactement un objet, bien qu’il puisse être utilisé comme un ensemble utilisant la flèche
(->).

5.7 Navigation au travers des associations qualifiées


Les associations qualifiées utilisent un ou plusieurs attributs qualifiés pour sélectionner les objets à
l’extrémité opposée de l’association. Pour les parcourir, on peut ajouter les valeurs aux qualificateurs pour la
navigation. Ceci est fait en utilisant des crochets, à la suite du nom de rôle. Il est autorisé de sauter par
dessus les valeurs du qualificateur, dans ce cas le résultat sera constitué de tous les objets à l’autre
extrémité de l’association.

context Bank inv:


self.customer

Fournit comme résultat un ensemble Set(Person) contenant tous les clients de la banque

self.customer[8764423]

11
Hiérarchie
_____________________________________________________________________________ 14
Le Langage UML 2.0 Claude Belleil Université de Nantes
Fournit comme résultat une personne ayant le compte bancaire n°8764423

S’il y a plus d’un attribut qualifié, les valeurs sont séparées par des virgules. Il n’est pas possible de spécifier
partiellement des valeurs d’attributs.

5.8 Utilisation des noms de chemins pour les paquetages et les


propriétés.

En UML, différents types sont organisés en paquetage. OCL fournit une méthode pour faire référence de
façon explicite aux types des autres paquetages en utilisant les noms de chemins comme préfixe des noms
de paquetages. La syntaxe est la suivante :

Packagename::Typename

Cette utilisation des noms de chemins est transitive et peut être mise en oeuvre pour des paquetages inclus
dans d’autres paquetages :

Packagename1::Packagename2::Typename

5.9 Accès aux propriétés des super types


A chaque fois que des propriétés sont redéfinies dans un type, la propriété des super types peut être atteinte
en utilisant la même syntaxe des chemins.
Quand on a une classe B comme un sous type de la classe A et une propriété p1 à la fois de A et de B, on
peut écrire.

context B inv:
self.oclAsType(A).p1 -- accès à la propriété p1 définie dans A
self.p1 -- accès à la propriété p1 définie dans B

L’exemple suivant illustre la nécessité de l’utilisation des noms de chemins.

Figure 3 : Ambiguïté de parcours


_____________________________________________________________________________ 15
Le Langage UML 2.0 Claude Belleil Université de Nantes
Dans ce fragment de modèle, il existe une ambiguïté avec l’expression OCL sur Dependency:

context Dependency inv:


self.source <> self

Celle-ci peut avoir pour signification une association normale de navigation qui est héritée de
ModelElement. Mais elle peut également signifier une navigation au travers du lien en pointillés en tant que
classe association. Les deux parcours possibles utilisent le même nom de rôle. Aainsi, l’ambiguïté subsiste.
En utilisant oclAsType() nous pouvons les distinguer l’une de l’autre :

context Dependency
inv: self.oclAsType(Dependency).source
inv: self.oclAsType(ModelElement).source

5.10 Caractéristiques prédéfinies sur tous les objets

Il existe plusieurs caractéristiques qui s’appliquent à l’ensemble des objets et qui sont prédéfinis en OCL:

oclIsTypeOf(t : OclType) : Boolean


oclIsKindOf(t : OclType) : Boolean
oclInState(s : OclState) : Boolean
oclIsNew() : Boolean
oclAsType(t : OclType) : instance of OclType

L’opération oclAsType fournit un résultat à vrai si le type de self et t sont les mêmes.

Par exemple :

context Person
inv: self.oclIsTypeOf( Person ) -- est vrai
inv: self.oclIsTypeOf( Company) -- est faux

L’expression ci-dessus permet d’accéder directement au type direct d’un objet. oclIsKindOf détermine si
t est soit le type direct ou un des super types d’un objet.

L’opération oclInState(s) fournit un résultat à vrai si l’objet est dans un état s. Les valeurs de s sont les
noms des états dans le diagramme d’états-transitions lié au classificateur de l’objet. Pour emboîter les états,
les noms des états peuvent être combinés en utilisant le signe « :: ».

Figure 4: Propriétés sur un automate à états


_____________________________________________________________________________ 16
Le Langage UML 2.0 Claude Belleil Université de Nantes
Dans l’exemple ci-dessus les valeurs de s peuvent être On, Off, Off ::Standby, Off ::NoPower.
Si le classificateur de l’objet est associé au diagramme d’états-transitions ci-dessus, les expressions OCL
suivantes sont valides:

object.oclInState(On)
object.oclInState(Off)
object.oclInstate(Off::Standby)
object.oclInState(Off:NoPower)

S’il y a plusieurs diagrammes d’états attachés au classificateur de l’objet, alors le nom d’un l’état peut être
préfixé par le nom du diagramme d’états contenant l’état et le double « :: » comme avec les états
emboîtés.

5.11 Caractéristiques sur les classes elles-mêmes

Toutes les propriétés présentées jusqu’à présent en OCL, sont des propriétés sur des instances de classes.
Les types sont, soit définis en OCL, soit définis dans le modèle de classes. En OCL, il est également
possible d’utiliser des caractéristiques définies sur les types/classes eux-mêmes. Ce sont, par exemple, les
caractéristiques définies dans le modèle de classe. De plus, plusieurs caractéristiques sont prédéfinies sur
chacun des types.
La caractéristique prédéfinie la plus importante sur chaque type est allInstances, qui fournit en résultat
l’ensemble (Set) de toutes les instances du type. Si nous voulons garantir que toutes les instances de
Person ont des noms uniques nous pouvons écrire :

context Person inv:


Person.allInstances->forAll(p1, p2 |
p1 <> p2 implies p1.name <> p2.name)

Person.allInstances est l’ensemble de toutes les personnes et est du type Set(Person). Il


représente l’ensemble de toutes les personnes qui existent au moment où l’expression est évaluée.

5.12 Collections

Un parcours simple a le plus souvent pour résultat : un ensemble (Set),

des parcours combinés : un sac (Bag)


des parcours sur des associations ornées de rôles avec une contrainte {ordered} une séquence
(Sequence).

Par conséquent, le type collection jouent un rôle important dans les expressions OCL.

Le type collection est prédéfini en OCL. Il comprend un grand nombre d’opérations prédéfinies pour
permettre à l’auteur des expressions OCL de manipuler ces collections.
Avec la définition d’OCL en tant que langage d’expression, les opérations sur les collections de changent
jamais les collections. isQuery est toujours vrai. Elles peuvent fournir un résultat sous la forme d’une
collection, mais plutôt que de changer la collection d’origine, elles fournissent le résultat dans une nouvelle
collection.

Collection est un type abstrait avec des types de collections concrètes comme sous types. OCL distingue
trois types différents types de collections :

l’ensemble (Set),

_____________________________________________________________________________ 17
Le Langage UML 2.0 Claude Belleil Université de Nantes
la séquence (Sequence)
le sac (Bag).

Set correspond à l’ensemble de type mathématique. Il ne peut pas contenir d’éléments dupliqués.

Set { 1 , 2 , 5 , 88 }
Set { 'apple' , 'orange', 'strawberry' }

Bag est comme un Set qui peut contenir des doublons, c'
est-à-dire que le même élément peut être dans un
Bag deux ou plusieurs fois.

Bag {1 , 3 , 4, 3, 5, 1 }

Une séquence (Sequence) est comme un sac (Bag) dans lequel les éléments sont ordonnés.

Sequence {1 , 1, 3 , 3, 4, 5 }

Les sacs (Bag) et les ensembles (Set) n’ont pas ordre défini. Set, Sequence et Bag peuvent être spécifiés
par un littéral. Des petites accolades (curly brackets) encadrent les éléments de la collection qui sont
séparés par des virgules. Le type de la collection est écrit avant les accolades.

Du fait de l’utilisation fréquente de séquences consécutives de nombres entiers, il existe un littéral de


séparation pour les créer. Les éléments entre les accolades peuvent être remplacés par une spécification
d’intervalle qui consiste en deux expressions de type Integer, Int-expr1 et Int-expr2 séparées par
« .. ». Ceci indique tous les Entiers compris entre les valeurs de Int-expr1 et Int-expr2, incluant les
valeurs de Int-expr1 et Int-expr2 elles-mêmes :

Sequence{ 1..(6 + 4) }
Sequence{ 1..10 }

Sont identiques à

Sequence{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }

La liste complète des opérations sur collection est décrite dans le document annexe. Les Collections
peuvent être spécifiées par un littéral comme décrit ci-dessous. La seule autre façon d’obtenir une collection
est la navigation. Pour être plus précis, la seule façon d’obtenir Set, Sequence ou Bag est :

1. Un littéral qui fournira un résultat sous la forme d’un ensemble, d’une séquence ou d’un sac :

Set {1 , 2, 3 , 5 , 7 , 11, 13, 17 }


Sequence {1 , 2, 3 , 5 , 7 , 11, 13, 17 }
Bag {1, 2, 3, 2, 1}

2. Un parcours commençant à partir d’un objet peut fournir en résultat une collection:

context Company inv:


self.employee

3. Des opérations sur des collections peuvent fournir une nouvelle collection:

collection1->union(collection2)

_____________________________________________________________________________ 18
Le Langage UML 2.0 Claude Belleil Université de Nantes
5.13 Collections de collections

Dans le langage OCL, toutes les collections de collections sont automatiquement mises à plat. Ainsi, les
deux expressions suivantes ont la même valeur :

Set{ Set{1, 2}, Set{3, 4}, Set{5, 6} }


Set{ 1, 2, 3, 4, 5, 6 }

5.14 Hiérarchie de type collection et règles de conformité de types

En plus des règles de conformité de types vues au paragraphe 4.4, les règles suivantes sont valides pour
tous les types incluant les types collection :

• Chaque type Collection(X) est un sous type de OclAny. Les types Set (X), Bag (X) et
Sequence (X) sont tous des sous types de Collection (X).

Les règles de conformité de types sont les suivantes pour les types collection :

• Un Type1 est conforme à un Type2 quand ils sont identiques (règle standard pour tous les types)

• Un Type1 est conforme à un Type2 quand il est un sous type du Type2 (règle standard pour tous
les types)

• Une Collection(Type1) est conforme à une Collection(Type2) quand le Type1 et le Type2 sont
conformes.

• La conformité de type est transitive: si un Type1 est conforme à un Type2, et que le Type2 est
conforme à un Type3, alors les Type1 et Types3 sont conformes (règle standard pour tous les types)

Par exemple si Bicycle et Car sont deux sous types distincts de Transport:

Set(Bicycle) est conforme à Set(Transport)


Set(Bicycle) est conforme à Collection(Bicycle)
Set(Bicycle) est conforme à Collection(Transport)

On notera que Set(Bicycle) n’est pas en conformité avec Bag(Bicycle) … Ce sont deux sous types
de Collection (Bicycle) au même niveau dans la hiérarchie.

5.15 Valeurs préalables dans les Post Conditions

Comme cela a été vu à la section 3.4, OCL peut être utilisé pour spécifier des Pré et Post conditions sur des
opérations et des méthodes en UML.

Dans une post condition, l’expression peut faire référence à deux ensembles de valeurs pour chaque
propriété d’un objet :

• La valeur d’une propriété au début de l’opération ou de la méthode


• La valeur d’une propriété après l’exécution de l’opération ou de la méthode
_____________________________________________________________________________ 19
Le Langage UML 2.0 Claude Belleil Université de Nantes
La valeur d’une propriété dans une post condition correspond aux valeurs après exécution de l’opération.
Pour faire référence à la valeur d’une propriété au début de l’opération on post fixe le nom de la propriété
avec le mot réservé « @pre » :

context Person::birthdayHappens()
post: age = age@pre + 1

La propriété age fait référence à la propriété de l’instance de Person sur laquelle s’exécute l’opération. La
propriété age@pre fait reference à la valeur de la propriété age de Person qui execute l’opération, au debut
de l’opération.

Si la propriété a des paramètres, @pre est postfixée du nom de la propriété avant les paramètres :

context Company::hireEmployee(p : Person)


post: employees = employees@pre->including(p) and
stockprice() = stockprice@pre() + 10

alors l’opération ci-dessus peut également être spécifiée conjointement par une pré et post condition

context Company::hireEmployee(p : Person)


pre : not employee->includes(p)
post: employees->includes(p) and
stockprice() = stockprice@pre() + 10

Quand la pré valeur de la propriété est prise et évaluée pour un objet, toutes les propriétés suivantes
auxquelles on a accès sont des valeurs nouvelles de cet objet (jusqu’à l’exécution de l’opération)

ainsi:

a.b@pre.c

prend l’ancienne valeur de la propriété b de a, appelée x et ensuite la nouvelle valeur c de x

a.b@pre.c@pre

prend l’ancienne valeur de la propriété b de a, appelée x, et ensuite l’ancienne valeur de c de x.

La notation post fixée “@pre” n’est autorisée que dans les expressions OCL qui font partie d’une post
condition. Ainsi, pour une propriété courante d’un objet qui a été détruit pendant l’exécution de l’opération, le
résultat est indéfini. Egalement, faisant référence à la valeur précédente d’un objet qui a été créé pendant
l’exécution de l’opération, le résultat est indéfini.

6 Les opérations sur les collections


OCL définit plusieurs opérations sur les types Collection. Ces opérations ont spécifiquement la capacité de
générer de façon souple et puissante de nouvelles collections à partir de celles qui existent. Les différentes
constructions sont décrites dans les paragraphes suivants.

6.1 Les opérations Select et Reject


Parfois une expression utilisant des opérations et des navigations fournit comme résultat une collection alors
que nous ne nous intéressons qu’à un sous ensemble de cette collection. OCL dispose d’opérateurs
_____________________________________________________________________________ 20
Le Langage UML 2.0 Claude Belleil Université de Nantes
spéciaux pour réaliser une sélection à partir d’une collection spécifique. La sélection spécifie un sous
ensemble de la collection. Une sélection est une opération sur une collection et est réalisée en utilisant la
flèche :

collection->select( ... )

Le paramètre de la sélection possède une syntaxe spéciale qui permet à la sélection de spécifier quels
éléments de la collection nous souhaitons sélectionner. Il existe trois formes différentes, parmi lesquelles
la plus simple est la suivante :

collection->select( boolean-expression )

Cela fournit comme résultat une collection qui contient tous les éléments de la collection pour lesquels
l’expression booléenne a été évaluée à Vrai. Pour trouver le résultat de cette expression, l’expression
boolean-expression est évaluée pour chaque élément de la collection. Si l’évaluation est Vraie,
l’élément est inclus dans la « collection résultat », sinon, il ne l’est pas. A titre d’exemple, l’expression OCL
suivante spécifie que la collection de tous les employés ayant plus de 50 ans n’est pas vide.

context Company inv:


self.employee->select(age > 50)->notEmpty()

self.employee est du type Set(Person). La sélection prend une personne à partir de self.employee
puis évalue age > 50 pour cette personne. Si le résultat est vrai, alors la personne est mise dans
l’ensemble résultat.

Comme il a été montré dans l’exemple précédent, le contexte pour l’expression dans l’argument du select
est l’élément de la collection sur lequel le select est invoqué. Ainsi, la propriété age est prise dans le
contexte d’une personne.

Dans l’exemple ci-dessus, il est impossible de faire explicitement référence aux personnes elles-mêmes. On
peut seulement faire référence à leurs propriétés. Afin de pouvoir faire référence aux personnes elles-
mêmes, il existe une syntaxe plus générale pour l’expression de sélection :

Collection->select( v | boolean-expression-with-v )

La variable v est appelée l’itérateur. Quand la selection est évaluée, v réalise des itérations sur la collection
et boolean-expression-with-v est évalué pour chaque valeur de v. La variable v est une référence à
l’objet à partir de la collection et peut être utilisée pour faire référence aux objets eux-mêmes à partir de la
collection. Les deux exemples ci-dessous sont identiques :

context Company inv:


self.employee->select(age > 50)->notEmpty()

context Company inv:


self.employee->select(p | p.age > 50)->notEmpty()

Le résultat d’une sélection complète est une collection de personnes pour lesquelles l’expression p.age >
50 est évaluée à Vrai. C’est un sous ensemble de self.employee.

Comme extension finale pour la syntaxe du select, le type attendu de la variable v peut être donné. Le select
s’écrit alors :

Collection->select( v : Type | boolean-expression-with-v )

_____________________________________________________________________________ 21
Le Langage UML 2.0 Claude Belleil Université de Nantes
La signification de cela est que les objets de la collection doivent être du type Type. L’exemple suivant est
identique aux précédents :

context Company inv:


self.employee.select(p : Person | p.age > 50)->notEmpty()

La syntaxe complète du select ressemble à l’une des formes suivantes:

collection->select( v : Type | boolean-expression-with-v )


collection->select( v | boolean-expression-with-v )
collection->select( boolean-expression )

L’opération reject est identique à l’opération select mais avec reject on obtient le sous ensemble de
tous les éléments de la collection pour lesquels l’expression est évaluée à Faux. La syntax est identique à
celle du select :

Collection->reject( v : Type | boolean-expression-with-v )


Collection->reject( v | boolean-expression-with-v )
Collection->reject( boolean-expression )

A titre d’exemple, spécifions que la collection de tous les employés qui ne sont pas mariés est vide:

context Company inv:


self.employee->reject( isMarried )->isEmpty()

L’opération de rejet est disponible en OCL pour des raisons de commodité car chaque rejet peut être réécrit
comme une sélection avec une expression de négation. Ainsi, les deux expressions suivantes sont
identiques :

Collection->reject( v : Type | boolean-expression-with-v )


collection->select( v : Type | not (boolean-expression-with-v) )

6.2 L’opération Collect


Comme il a été montré dans la section précédente, l' opération select ou reject fournit toujours un
résultat sous la forme d' une sous collection à partir de la collection d’origine. Lorsque nous voulons spécifier
une collection qui est dérivée à partir d'une autre collection, mais qui contient des objets différents de ceux
de la collection d' origine, c'est à dire qui ne constitue pas une sous collection, nous pouvons utiliser
l'
opération collect. Celle-ci utilise la même syntaxe que les opération select et reject et s' écrit de la
façon suivante:

collection->collect( v : Type | expression-with-v )


collection->collect( v | expression-with-v )
collection->collect( expression )

_____________________________________________________________________________ 22
Le Langage UML 2.0 Claude Belleil Université de Nantes
La valeur de l'
opération collect est constituée par la collection des résultats de toutes les évaluations de
expression-with-v

Un exemple: spécifier la collection des dates de naissances (birthDates) pour tous les employés dans le
contexte d'
une entreprise (company)

self.employee->collect( birthDate )
self.employee->collect( person | person.birthDate )
self.employee->collect( person : Person | person.birthDate )

Une question importante ici est que la collection résultat n'


est pas un ensemble, mais un sac (Bag). Quand
plusieurs employés ont la même date de naissance, cette valeur apparaîtra plusieurs fois dans le résultat. Le
sac résultant de l'
opération collect a toujours la même dimension que la collection d' origine. Il est possible
de construire un ensemble (Set) à partir d'un sac (Bag) en utilisant la propriété asSet sur le sac.
L'expression suivante fournit comme résultat l' ensemble (Set) des différentes dates de naissance des
employés de l' entreprise:

self.employee->collect( birthDate )->asSet

Parce que la navigation au travers de plusieurs objets est une action très commune, il existe une notation
simplifiée pour l'
opération Collect qui rend les expressions OCL plus lisibles.

Au lieu de :

self.employee->collect(birthdate)

on peut écrire:

self.employee.birthdate

En général, quand on applique une propriété aux objets d' une collection. Celle-ci sera automatiquement
interprétée comme un Collect sur les membres de la collection avec la propriété spécifiée.
Ainsi, pour tout nom de propriété (propertyname) qui est défini comme une propriété sur les objets de la
collection, les deux expressions suivantes sont équivalentes:

collection.propertyname
collection->collect(propertyname)

Également si la propriété est paramètrisée:

collection.propertyname(par1, par2, ...)


collection->collect(propertyname(par1, par2, ...)

6.3 L'opération forAll


A chaque fois qu'
une contrainte est nécessaire sur l'
ensemble des éléments d'une collection, l'
opération
forAll permet de spécifier une expression booléenne qui doit être appliquée à tous les objets de la
collection.

collection->forAll( v : Type | boolean-expression-with-v )


collection->forAll( v | boolean-expression-with-v )
collection->forAll( boolean-expression )
_____________________________________________________________________________ 23
Le Langage UML 2.0 Claude Belleil Université de Nantes
Cette expression forAll renvoie un booléen. Le résultat est vrai si boolean-expression-with-v est
vraie pour tous les éléments de la collection. Si boolean-expression-with-v est faux pour un v ou plus
dans la collection, alors l'
expression complète est évaluée à faux. Par exemple, dans le contexte Company:

context Company
inv: self.employee->forAll( forename = 'Jack' )
inv: self.employee->forAll( p | p.forename = 'Jack' )
inv: self.employee->forAll( p : Person | p.forename = 'Jack' )

Ces invariants sont évalués à vrai si la caractéristique forename de chaque employé est égale à «Jack».
L’opération forAll possède une variante avec laquelle on peut mettre en œuvre plus d’un itérateur. Deux
itérateurs peuvent être utilisés sur la collection complète. C’est un forAll sur le produit cartésien de la
collection sur elle-même.

context Company inv:


self.employee->forAll( e1, e2 |
e1 <> e2 implies e1.forename <> e2.forename)

context Company inv:


self.employee->forAll( e1, e2 : Person |
e1 <> e2 implies e1.forename <> e2.forename)

Cette expression est évaluée à vrai si les forename de tous les employés sont différents. C’est
sémantiquement équivalent à :

context Company inv:


self.employee->forAll(e1 | self.employee->forAll (e2 |
e1 <> e2 implies e1.forename <> e2.forename)))

6.4 L’opération exists


Souvent on a besoin de savoir si il y a au moins un élément dans une collection pour laquelle une contrainte
existe. L’opération exists permet de spécifier une expression booléenne qui doit convenir pour au moins
un objet de la collection :

collection->exists( v : Type | boolean-expression-with-v )


collection->exists( v | boolean-expression-with-v )
collection->exists( boolean-expression )

Le résultat de l’opération exists est un booléen. Le résultat est vrai si boolean-expression-with-v


est vrai pour au moins un élément de la collection. Si boolean-expression-with-v est évalué à faux
pour tout v dans la collection, alors l’expression complète est évaluée à faux. Par exemple dans le
context de Company :

context Company inv:


self.employee->exists( forename = 'Jack' )

context Company inv:


self.employee->exists( p | p.forename = 'Jack' )

context Company inv:


_____________________________________________________________________________ 24
Le Langage UML 2.0 Claude Belleil Université de Nantes
self.employee->exists( p : Person | p.forename = 'Jack' )

Ces expressions sont évaluées à vrai si la caractéristique forename d’au moins un employé est égale à
« Jack ».

6.5 L’opération iterate


L’opération d’itération (iterate) est légèrement plus complexe, mais très générale. Les opérations
select, forAll, exists, collect, elect peuvent toutes être décrites en termes d’itération. Une
accumulation construit une valeur par itération sur une collection.

collection->iterate( elem : Type; acc : Type = <expression> |


expression-with-elem-and-acc )

La valeur elem est l’itérateur, comme dans la définition de select, forAll, etc.
La variable acc est l’accumulateur. L’accumulateur prend une valeur initiale <expression>. Quand
iterate est évalué, elem réalise une itération sur la collection et expression-with-elem-and-acc est
évaluée pour chaque élément. Après chaque évaluation de expression-with-elem-and-acc, sa valeur
est assignée à acc. De cette façon, la valeur de acc est construite pendant l’itération de la collection.
L’opération collect décrite en termes d’iterate ressemblera à :

collection->collect(x : T | x.property)

qui est identique à

collection->iterate(x : T; acc : T2 = Bag{} |


acc->including(x.property))

Ou bien, écrit en pseudo code Java, le résultat de l’itération peut être calculé comme suit:

iterate(elem : T; acc : T2 = value)


{
acc = value;
for(Enumeration e = collection.elements() ;
e.hasMoreElements(); )
{
elem = e.nextElement();
acc = <expression-with-elem-and-acc>
}
}

6.6 Itérateurs sur les opérations des collections


Les opérations sur les collections qui prennent une OclExpression comme paramètre, doivent toutes
avoir une déclaration optionnelle d’itérateur. Pour toute opération nommée op, la syntaxe des options est la
suivante :

collection->op( iter : Type | OclExpression )


collection->op( iter | OclExpression )
collection->op( OclExpression )

_____________________________________________________________________________ 25
Le Langage UML 2.0 Claude Belleil Université de Nantes
6.7 Résolution des propriétés
Pour toute propriété (attribut, opération ou navigation) la notation complète comprend l’objet dans lequel la
propriété est extraite. Comme cela a été vu dans le paragraphe 6.3.3 sur les invariants, self peut être traité
de façon implicite. Il en est de même pour les variables d’itérations dans les opérations sur les collections.
Dans une expression, quand un itérateur n’est pas explicitement cité, une variable implicite est introduite.
Par exemple dans :

context Person inv:


employer->forAll( employee->exists( lastName = name) )

trois variables implicites sont introduites. La première est self, qui est toujours l’instance à partir de laquelle
la contrainte débute. Ensuite, un itérateur implicite est introduit par forAll et un troisième par exists. Ces
variables ne sont pas nommées. Les propriétés employer, employee, lastName et name ont toutes
un objet sur lequel elles sont appliquées.

A la place d’employer, il y a une variable implicite : self:Person.Par conséquent, employer doit


être une propriété de self.
A la place d’employee, il y a deux variables implicites : self:Person et iter1:Company. Par
conséquent, employer doit être une propriété soit de self soit d’iter1. Si employee est une
propriété à la fois de self et d’iter1, alors il n’y a pas d’ambiguïté et l’instance sur laquelle
employee est appliquée doit être établit explicitement. Dans ce seul cas, iter1:employee est
possible.
A la place de lastName et name il y a trois variables implicites : self:Person, iter1:Company et
iter2:Person. Donc, lastName et name doivent être à la fois des propriétés soit de self, d’iter1
ou d’iter2. La propriété name est une propriété d’iter1. Cependant, lastName est une propriété à
la fois de self et d’iter2. C’est ambigu et par conséquent l’expression OCL est incorrecte.
L’expression doit établir soit self.lastName ou bien définir l’itérateur iter2 de façon explicite et
établir iter2.lastName.

Les deux contraintes suivantes sont correctes :

context Person
inv: employer->forAll( employee->exists( p | p.lastName = name) )
inv: employer->forAll( employee->exists( self.lastName = name) )

7 Types OCL prédéfinis


(voir le document annexe: OCL_Annexe.PDF)

_____________________________________________________________________________ 26
Le Langage UML 2.0 Claude Belleil Université de Nantes
Index du texte:

1 Préambule................................................................................................................................................. 1
1.1 Pourquoi OCL?................................................................................................................................. 1
1.2 Comment utiliser OCL ...................................................................................................................... 2
2 Introduction ............................................................................................................................................... 2
2.1 Légende ........................................................................................................................................... 2
2.2 Diagramme de classes..................................................................................................................... 3
3 Lien avec le méta modèle UML ................................................................................................................ 4
3.1 Self ................................................................................................................................................... 4
3.2 Spécification du contexte UML......................................................................................................... 4
3.3 Les invariants ................................................................................................................................... 4
3.4 Pré et post conditions....................................................................................................................... 5
3.5 Le contexte Package........................................................................................................................ 5
3.6 Expressions générales ..................................................................................................................... 6
4 Valeurs élémentaires et types................................................................................................................... 6
4.1 Types provenant du modèle UML .................................................................................................... 6
4.2 Types énumération........................................................................................................................... 6
4.3 L’expression Let et les contraintes de définition............................................................................. 7
4.4 Conformité de types ......................................................................................................................... 7
4.5 Re typage ou consolidation.............................................................................................................. 8
4.6 Règles de précédence ..................................................................................................................... 8
4.7 Utilisation des opérateurs infixes ..................................................................................................... 9
4.8 Les commentaires ............................................................................................................................ 9
4.9 Valeurs indéfinies ........................................................................................................................... 10
5 Objets et propriétés................................................................................................................................. 10
5.1 Les propriétés................................................................................................................................. 10
5.2 Propriétés: attributs ........................................................................................................................ 10
5.3 Propriétés: Opérations ................................................................................................................... 11
5.4 Propriétés: Extrémités (rôles) d’associations et navigation ........................................................... 11
5.4.1 Absence de Nom de rôle ........................................................................................................... 12
5.4.2 Navigation sur des associations avec des cardinalités Zéro ou un ........................................... 12
5.4.3 Propriétés combinées ................................................................................................................ 13
5.5 Navigation et types d’associations ................................................................................................. 13
5.6 Navigation à partir des classes associations ................................................................................. 14
5.7 Navigation au travers des associations qualifiées ......................................................................... 14
5.8 Utilisation des noms de chemins pour les paquetages et les propriétés. ...................................... 15
5.9 Accès aux propriétés des super types ........................................................................................... 15
5.10 Caractéristiques prédéfinies sur tous les objets ............................................................................ 16
5.11 Caractéristiques sur les classes elles-mêmes ............................................................................... 17
5.12 Collections...................................................................................................................................... 17
5.13 Collections de collections ............................................................................................................... 19
5.14 Hiérarchie de type collection et règles de conformité de types...................................................... 19
5.15 Valeurs préalables dans les Post Conditions................................................................................. 19
6 Les opérations sur les collections ........................................................................................................... 20
6.1 Les opérations Select et Reject ..................................................................................................... 20
6.2 L’opération Collect.......................................................................................................................... 22
6.3 L'opération forAll ............................................................................................................................ 23
6.4 L’opération exists ........................................................................................................................... 24
6.5 L’opération iterate........................................................................................................................... 25
6.6 Itérateurs sur les opérations des collections.................................................................................. 25
6.7 Résolution des propriétés .............................................................................................................. 26
7 Types OCL prédéfinis ............................................................................................................................. 26

_____________________________________________________________________________ 27
Le Langage UML 2.0 Claude Belleil Université de Nantes
Index des figures:

Figure 1 : Diagramme de classe "exemple" ...................................................................................................... 3


Figure 2 : navigation récursive sur une classe association ............................................................................. 13
Figure 3 : Ambiguïté de parcours .................................................................................................................... 15
Figure 4: Propriétés sur un automate à états .................................................................................................. 16

_____________________________________________________________________________ 28
Le Langage UML 2.0 Claude Belleil Université de Nantes

Vous aimerez peut-être aussi