Vous êtes sur la page 1sur 54

Object Constraint Language (OCL)

Eric Cariou
Universit de Pau et des Pays de l'Adour
UFR Sciences Pau Dpartement Informatique
Eric.Cariou@univ-pau.fr
1

Plan
1. Pourquoi OCL ? Introduction par l'exemple
2. Les principaux concepts d'OCL
3. Exemple d'application sur un autre modle

Exemple d'application

Application banquaire

Des comptes banquaires


Des clients
Des banques

Spcification

Un compte doit avoir un solde toujours positif


Un client peut possder plusieurs comptes
Un client peut tre client de plusieurs banques
Un client d'une banque possde au moins un compte dans
cette banque
Une banque gre plusieurs comptes
Une banque possde plusieurs clients
3

Diagramme de classe
Banque

*
clients

Compte
int solde
crditer(int)
dbiter(int)
int getSolde()

Personne
int age
propritaire

Manque de prcision

Le diagramme de classe ne permet pas d'exprimer


tout ce qui est dfini dans la spcification informelle
Exemple

Le solde d'un compte doit toujours tre positif : ajout d'une


contrainte sur cet attribut

Le diagramme de classe permet-il de dtailler


toutes les contraintes sur les relations entre les
classes ?

Diagramme d'instances
Banque:B1

Banque

*
clients

Personne
int age

Personne:P1

propritaire 1

Compte
int solde
crditer(int)
dbiter(int)
int getSolde()

Compte:Co1

Banque:B2
Compte:Co2

*
{ solde > 0 }

Personne:P2

Diagramme d'instances valide vis--vis du diagramme


de classe et de la spcification attendue
6

Diagramme d'instances
*

Banque

Banque:B1
clients

Personne
int age

Compte:Co1
Personne:P1

propritaire 1

Compte
int solde
crditer(int)
dbiter(int)
int getSolde()

Banque:B2

*
{ solde > 0 }

Personne:P2

Compte:Co2

Diagramme d'instances valide vis--vis du diagramme de classe


mais ne respecte pas la spcification attendue

Une personne a un compte dans une banque o elle n'est pas cliente
Une personne est cliente d'une banque mais sans y avoir de compte
7

Diagrammes UML insuffisants

Pour spcifier compltement une application

Comment exprimer ces contraintes ?

Diagrammes UML seuls sont gnralement insuffisants


Ncessit de rajouter des contraintes
Langue naturelle mais manque de prcision, comprhension
pouvant tre ambige
Langage formel avec smantique prcise : par exemple
OCL

OCL : Object Constraint Language

Langage de contraintes orient-objet


Langage formel (mais simple utiliser) avec une syntaxe,
une grammaire, une smantique (manipulable par un outil)
S'applique entre autres sur les diagrammes UML ou MOF
8

Plan
1. Pourquoi OCL ? Introduction par l'exemple
2. Les principaux concepts d'OCL
3. Exemple d'application sur un autre modle

Le langage OCL

Norme de l'OMG

Version courante : version 2.0


Peut s'appliquer sur tout type de modle, indpendant d'un
langage de modlisation donn

OCL permet principalement d'exprimer deux types de


contraintes sur l'tat d'un objet ou d'un ensemble
d'objets

Des invariants qui doivent tre respects en permanence


Des pr et post-conditions pour une opration

Prcondition : doit tre vrifie avant l'excution


Postcondition : doit tre vrifie aprs l'excution

Attention

Une expression OCL dcrit une contrainte respecter et


non pas le code d'une mthode

10

Usage d'OCL sur l'application banquaire


Banque

*
clients

Personne
int age
propritaire 1

Compte
int solde
crditer(int)
dbiter(int)
int getSolde()

context Compte
inv: solde > 0
context Compte : dbiter(somme : Integer)
pre: somme > 0
post: solde = solde@ pre - somme
context Compte
inv: banque.clients -> includes (propritaire)

Avantage d'OCL : langage formel permettant de prciser


clairement de la smantique sur les modles UML
11

Utilisation d'OCL dans le cadre d'UML

OCL peut s'appliquer sur la plupart des


diagrammes UML
Il sert, entre autres, spcifier des

Invariants sur des classes


Pr et postconditions sur des oprations
Gardes sur transitions de diagrammes d'tats ou de
messages de diagrammes de
squence/collaboration
Des ensembles d'objets destinataires pour un envoi
de message
Des attributs drivs
Des strotypes
12
...

Contexte

Une expression OCL est toujours dfinie dans


un contexte

Ce contexte est l'instance d'une classe

Mot-cl : context
Exemple

context Compte
L'expression OCL s'applique la classe Compte,
c'est--dire toutes les instances de cette classe

13

Invariants

Un invariant exprime une contrainte sur un


objet ou un groupe d'objets qui doit tre
respecte en permanence
Mot-cl : inv
Exemple

context Compte
inv: solde > 0
Pour toutes les instances de la classe Compte,
l'attribut solde doit toujours tre positif

14

Pr et postconditions

Pour spcifier une opration

Prcondition : tat qui doit tre respect avant l'appel de


l'opration
Postcondition : tat qui doit tre respect aprs l'appel de
l'opration
Mots-cls : pre et pos t

Dans la postcondition, deux lments particuliers sont


utilisables

Attribut res ult : rfrence la valeur retourne par l'opration

mon_attribut@ pre : rfrence la valeur de mon_attribut


avant l'appel de l'opration

Syntaxe pour prciser l'opration

context ma_classe::mon_op(liste_param) : type_retour


15

Pr et postconditions

Exemples

context Compte::dbiter(somme : Integer)


pre: somme > 0
post: solde = solde@ pre somme

context Compte::getSolde() : Integer


post: result = solde

La somme dbiter doit tre positive pour que l'appel de


l'opration soit valide
Aprs l'excution de l'opration, l'attribut solde doit avoir pour
valeur la diffrence de sa valeur avant l'appel et de la somme
passe en paramtre

Le rsulat retourn doit tre le solde courant

Attention

On ne dcrit pas comment l'opration est ralise mais des


contraintes sur l'tat avant et aprs son excution
16

Conception par contrat pour oprations

Pre et postconditions permettent de faire une


conception par contrat

Contrat pass entre l'appelant d'une opration et


l'appel (celui qui excute l'opration)
Si l'appelant respecte les contraintes de la
prcondition alors l'appel s'engage respecter la
post-condition

Si l'appelant ne respecte pas la prcondition, alors le


rsultat de l'appel est indfini

Pour exemple prcdent

Si l'appelant de l'opration dbiter passe une somme


positive en paramtre, alors le compte est bien dbit de
cette somme
17

Accs aux objets, navigation

Dans une contrainte OCL associe un objet, on


peut

Nommage des lments

Accder l'tat interne de cet objet (ses attributs)


Naviguer dans le diagramme : accder de manire
transitive tous les objets (et leur tat) avec qui il est en
relation
Attributs ou paramtres d'une opration : utilise leur nom
directement
Objet(s) en association : utilise le nom de la classe associe
(en minuscule) ou le nom du rle d'association du cot de
cette classe

Si cardinalit de 1 pour une association : rfrence


un objet
Si cardinalit > 1 : rfrence une collection d'objets

18

Accs aux objets, navigation

Exemples, dans contexte de la classe Compte

solde : attribut rfrenc directement


banque : objet de la classe Banque (rfrence via le nom de
la classe) associ au compte
propritaire : objet de la classe Personne (rfrence via le
nom de rle d'association) associe au compte
banque.clients : ensemble des clients de la banque associe
au compte (rfrence par transitivit)
banque.clients.age : ensemble des ges de tous les clients de
la banque associe au compte

Le propritaire d'un compte doit avoir plus de 18 ans

context Compte
inv: propritaire.age >= 18
19

Oprations sur objets et collections

OCL propose un ensemble de primitives utilisables sur les


collections

size() : retourne le nombre d'lments de la collection

isEmpty() : retourne vrai si la collection est vide

notEmpty() : retourne vrai si la collection n'est pas vide

includes(obj) : vrai si la collection inclut l'objet obj

excludes(obj) : vrai si la collection n'inclut pas l'objet obj

including(obj) : la collection rfrence doit tre cette collection en


incluant l'objet obj

excluding(obj) : idem mais en excluant l'objet obj

includesAll(ens) : la collection contient tous les lments de la


collection ens

excludesAll(ens) : la collection ne contient aucun des lments de la


collection ens

Syntaxe d'utilisation : objetOuCollection -> primitive

20

Oprations sur objets et collections

Exemples, invariants dans le contexte de la classe


Compte

propritaire -> notEmpty() : il y a au moins un objet Personne


associ un compte
propritaire -> size() = 1 : le nombre d'objets Personne
associs un compte est de 1
banque.clients -> size() >= 1 : une banque a au moins un client
banque.clients -> includes(propritaire) : l'ensemble des clients
de la banque associe au compte contient le propritaire du
compte
banque.clients.compte -> includes(self) : le compte appartient
un des clients de sa banque

self

pseudo-attribut rfrenant l'objet courant


21

Oprations sur objets et collections

Autre exemple

OclIsNew()

context Banque :: creerCompte(p : Personne) : Compte


post: result.oclIsNew() and
compte = compte@ pre -> including(result) and
p.compte = p.compte@ pre -> including(result) and
result.proprietaire = p and result.banque = self
Un nouveau compte est cr. La banque doit grer ce nouveau compte.
Le client pass en paramtre doit possder ce compte. Le nouveau
compte est retourn par l'opration.

Primitive indiquant qu'un objet doit tre cr pendant l'appel de


l'opration ( utiliser dans une postcondition)

And

Permet de dfinir plusieurs contraintes pour un invariant, une pr


ou postcondition
and = et logique : l'invariant, pr ou postcondition est vrai si
22
toutes les expressions relies par le and sont vraies

Relations ensemblistes entre


collections

union

intersection

Retourne l'union de deux collections


Retourne l'intersection de deux collections

Exemples

(col1 -> intersection(col2)) -> isEmpty()


Renvoie vrai si les collections col1 et col2 n'ont pas
d'lment en commun
col1 = col2 -> union(col3)
La collection col1 doit tre l'union des lments de col2
et de col3

23

Oprations sur lments d'une collection

OCL permet de vrifier des contraintes sur chaque lment


d'une collection ou de dfinir une sous-collection partir d'une
collection en fonction de certaines contraintes
Primitives offrant ces services et s'appliquant sur une
collection col

select : retourne le sous-ensemble de la collection col dont les lments


respectent la contrainte spcifie

reject : idem mais ne garde que les lments ne respectant pas la


contrainte

collect : retourne une collection (de taille identique) construite partir


des lments de col. Le type des lments contenus dans la nouvelle
collection peut tre diffrent de celui des lments de col.

exists : retourne vrai si au moins un lment de col respecte la


contrainte spcifie et faux sinon

forAll : retourne vrai si tous les lments de col respectent la contrainte


spcifie (pouvant impliquer la fois plusieurs lments de la collection)
24

Oprations sur lments d'une collection

Syntaxe de ces oprations : 3 usages

collection -> primitive( expression )


La primitive s'applique aux lments de la collection et
pour chacun d'entre eux, l'expression expression est
vrifie. On accde aux attributs/relations d'un lment
directement.
collection -> primitive( elt : type |expression)
On fait explicitement apparatre le type des lments de la
collection (ici type). On accde aux attributs/relations de
l'lment courant en utilisant elt (c'est la rfrence sur
l'lment courant)
collection -> primitive(elt |expression)
On nomme l'attribut courant (elt) mais sans prciser son
type
25

Oprations sur lments d'une collection

Dans le contexte de la classe Banque

compte -> select( c |c.solde > 1000)

compte -> reject( solde > 1000)

Retourne une collection contenant tous les comptes


banquaires dont le solde n'est pas suprieur 1000

compte -> collect( c : Compte |c.solde)

Retourne une collection contenant tous les comptes


banquaires dont le solde est suprieur 1000

Retourne une collection contenant l'ensemble des soldes de


tous les comptes

(compte -> select( solde > 1000 ))


-> collect( c |c.solde)

Retourne une collection contenant tous les soldes des comptes


dont le solde est suprieur 1000
26

Oprations sur lments d'une collection

context B anque
inv: not( clients -> exists (age < 18) )
Il n'existe pas de clients de la banque dont l'age est infrieur
18 ans

not

Prend la ngation d'une expression

context Personne
inv: Personne.allInstances() -> forA ll(p1, p2 |
p1 <> p2 implies p1.nom <> p2.nom)
Il n'existe pas deux instances de la classe Personne pour
lesquelles l'attribut nom a la mme valeur : deux personnes
diffrentes ont un nom diffrent

AllInstances()

Primitive s'appliquant sur une classe (et non pas un objet) et


retournant toutes les instances de la classe rfrence (ici la
classe Personne)

27

Types OCL : types de base

Types de base et exemples d'oprations associes

Integer

Real

1.5, -123.4
*, +, -, /, floor()

String

1, -2, 145
*, +, -, /, abs()

'bonjour'
concat(), size(), substring()

Boolean

true, false
And, or, not, xor, not, implies, if-then-else
La plupart des expressions OCL sont de types Boolean
Notamment les expressions formant les inv, pre et post

28

Types OCL : types de collection

3 (4) types de collection d'objets

Set : ensemble au sens mathmatique, pas de doublons, pas


d'ordre

Bag : comme un Set mais avec possibilit de doublons


Sequence : un Bag dont les lments sont ordonns

Exemples :

OrderedSet : idem mais avec ordre

{ 1, 4, 3, 5 } : Set(Integer)
{ 1, 4, 1, 3, 5, 4 } : Bag(Integer)
{ 1, 1, 3, 4, 4, 5 } : Sequence(Integer)

Notes

Un collect() renvoie toujours un Bag


Possibilit de transformer un type de collection en un autre
type de collection avec oprations OCL ddies
29

Types OCL : types de collection

Collections imbriques

Via navigation, on peut rcuprer des collections


ayant pour lments d'autres collections
Deux modes de manipulation

Explicitement comme une collection de collections [de


collections ...]
Collection unique : on aplatit le contenu de toutes les
collections imbriques en une seule un seul niveau

Opration flatten() pour aplatir une collection de collections

Tuples/n-uplet

Donnes contenant plusieurs champs

Ex: Tuple { nom:String = 'toto', age:Integer = 21 }

Peut manipuler ce type de donnes en OCL


30

Types OCL : conformance de types

Conformance de type

Prise en compte des spcialisations entre classes du modle


Oprations OCL ddies la gestion des types

oclIsTypeOf(type) : vrai si l'objet est du type type

oclIsKindOf(type) : vrai si l'objet est du type type ou un de ses soustypes

oclAsType(type) : l'objet est cast en type type

Types internes OCL

Conformance entre les types de collection

Collection est le super-type de Set, Bag et Sequence


Conformance entre collection et types des objets contenus
Set(T1) est conforme Collection(T2) si T1 est sous-type de T2 ...
Integer est un sous-type de Real
31

Conditionnelles

Certaines contraintes sont dpendantes


d'autres contraintes
Deux formes pour grer cela

if expr1 then expr2 else expr3 endif

Si l'expression expr1 est vraie alors expr2 doit tre vraie


sinon expr3 doit tre vraie

expr1 implies expr2

Si l'expression expr1 est vraie, alors expr2 doit tre vraie


galement.
Si expr1 est fausse, alors l'expression complte est vraie

32

Conditionnelles

context Personne inv:


if age < 18
then compte -> isEmpty()
else compte -> notEmpty()
endif
Une personne de moins de 18 ans n'a pas de compte
banquaire alors qu'une personne de plus de 18 ans possde
au moins un compte

context Personne inv:


compte -> notEmpty() implies banque -> notEmpty()
Si une personne possde au moins un compte banquaire,
alors elle est cliente d'au moins une banque
33

Commentaires et nommage de
contraintes

Commentaire en OCL : utilisation de -

Exemple
context Personne inv:
if age < 18
then compte -> isEmpty()
else compte -> notEmpty()
endif

-- vrifie age de la personne


-- pas majeur : pas de compte
-- majeur : doit avoir au moins un compte

On peut nommer des contraintes

Exemple

context Compte
inv soldePositif: solde > 0

context Compte::dbiter(somme : Integer)


pre sommePositive: somme > 0
post sommeD bite: solde = solde@ pre - somme
34

Variables

Pour faciliter l'utilisation de certains attributs ou


calculs de valeurs on peut dfinir des variables
Dans une contrainte OCL : let ... in ...

context Personne
inv: let argent = compte.solde -> sum() in
age >= 18 implies argent > 0

Une personne majeure doit avoir de l'argent

sum() : fait la somme de tous les objets de la collection

Pour l'utiliser partout : def

context Personne
def: argent : Integer = compte.solde -> sum()
context Personne
inv: age >= 18 implies argent > 0
35

Appels d'opration des classes

Dans une contrainte OCL : accs aux attributs,


objets ... en lecture
Possibilit d'utiliser une opration d'une classe dans
une contrainte

Si pas d'effets de bords (de type query)


Car une contrainte OCL exprime une contrainte sur un tat
mais ne prcise pas qu'une action a t effectue

Exemple :

context B anque
inv: compte -> forA ll( c |c.getSolde() > 0)
getSolde() est une opration de la classe Compte. Elle
calcule une valeur mais sans modifier l'tat d'un compte
36

Dfinition de fonctions de type query

Oprateur def permet galement de dfinir


des fonctions d'interrogation du modle (query)

Avec paramtres et type de retour au besoin


Pour faciliter la navigation et la slection d'lments
sur le modle

Exemple: les comptes dont le solde est


suprieur une certaine somme val

context B anque def: soldesSup(val : Integer) : Set(Compte) =


self.comptes -> select (c |c.solde > val)
S'utilise ensuite comme une opration de la classe Banque
dont on se sert pour crire une contrainte
context B anque
inv: self.soldesSup(1000) -> notEmpty()
37

Liens avec diagrammes d'tats


[ autoris ] activer
Cr

[ problmes ]
[ not(autoris) ]

fermer
dbloquer

Bloqu

fermer

Possibilit de rfrencer un tat d'un diagramme d'tats


associ l'objet

Ouvert

oclInState(etat) : vrai si l'objet est dans l'tat etat.


Pour sous-tats : etat1::etat2 si etat2 est un tat interne de etat1

Exemple

context Compte :: dbiter(somme : Integer)


pre: somme > 0 and self.oclInState(Ouvert)
L'opration dbiter ne peut tre appele que si le compte est
dans l'tat ouvert

38

Liens avec diagrammes d'tats

On ne peut pas avoir plus de 5 comptes ouverts


dans une mme banque
context Compte :: activer()
pre: self.oclInState(Cr) and
proprietaire.compte -> select( c |
self.banque = c.banque) -> size() < 5
post: self.oclInState(Ouvert)

On peut aussi exprimer la garde [ autoris ] en OCL

context Compte
def: autoris : B oolean =
proprietaire.compte -> select( c |
self.banque = c.banque) -> size() < 5
39

Enumeration

Utilisation d'une valeur d'une numration

NomEnum::valeur
Ancienne notation : #valeur
Personne
Gender sexe

Homme

Femme

<< enumeration >>


Gender
male
female

context Homme
inv: sexe = Gender::male
context Femme
inv: sexe = #female
40

Proprits

De manire gnrale en OCL, une proprit


est un lment pouvant tre

Accde la proprit d'un objet avec .


Exemples

Un attribut
Un bout d'association
Une opration ou mthode de type requte

context Compte inv: self.solde > 0


context Compte inv: self.getSolde() > 0

Accde la proprit d'une collection avec


->

On peut utiliser -> galement dans le cas d'un


41
objet (= collection d'1 objet)

Accs aux attributs pour les collections

Accs un attribut sur une collection

Exemple dans contexte de Banque :


compte.solde
Renvoie l'ensemble des soldes de tous les comptes

Forme raccourcie et simplifie de

compte -> collect (solde)

42

Proprits prdfinies en OCL

Pour objets

oclIsKindOf(type) : l'objet est du type type ou un de ses


sous-types

oclInState(tat) : l'objet est dans l'tat tat

oclIsTypeOf(type) : l'objet est du type type

oclIsNew() : l'objet est cr pendant l'opration

oclAsType(type) : l'objet est cast en type type

oclIsUndefined() : la proprit (association par exemple)


n'a pas t initialise (quivalent d'un null)

Pour collections

isEmpty(), notEmpty(), size(), sum()

includes(), excludes(), includingAll() ...


....

43

Rgles de prcdence

Ordre de prcdence pour les oprateurs/primitives


du plus au moins prioritaire

@pre
. et ->
not et * et /
+ et if then else endif
>, <, <= et >=
= et <>
and, or et xor
implies

Parenthses permettent de changer cet ordre

44

Plan
1. Pourquoi OCL ? Introduction par l'exemple
2. Les principaux concepts d'OCL
3. Exemple d'application sur un autre modle

45

Diagramme de classe
1 manager

Person

isMarried : Boolean
isUnemployed: Boolean
age: Integer
0..* employee
gender : Gender
0..1 wife
2 income() : Real
parents
0..1 husband
*
children
*
Account
Real balance
getBalance() : Real
deposit(sum : Real)
withdraw(sum : Real)

0..*

Company

employer 0..* stockPrice() : Real

Job
salary : Real
pay()
<< enumeration >>
Gender
male
female

Inspiration : normes OCL


46

Contraintes sur employs d'une


compagnie

Dans une compagnie, un manager doit travailler et avoir


plus de 40 ans
Le nombre d'employ d'une compagnie est non nul
context Company
inv:
self.manager.isUnemployed = false and
self.manager.age > 40 and
self.employee -> notEmpty()

47

Lien salaire/chomage pour une


personne

Une personne considre comme au chmage ne doit pas


avoir des revenus suprieurs 500
context Person
inv:
let money : Real = self.job.salary->sum() in
if isUnemployed then
money < 500
els e
money >= 500
endif

48

Contraintes sur les parents/enfants

Un enfant a un pre et une mre


context Person
def: parent1 = parents -> at(0)
def: parent2 = parents -> at(1)
context Person
inv:
if parent1.gender = #male
then
-- parent1 est un homme
parent2.gender = #female
els e
-- parent1 est une femme
parent2.gender = #male
endif
49

Contraintes sur les parents/enfants

Tous les enfants d'une personne ont bien cette personne


comme parent et inversement
context Person
inv:
children -> notEmpty() implies
children -> forAll ( p : Person |
p.parents -> includes(self))

context Person
inv:
parents -> forAll ( p : Person |
p.children -> includes (self))
Note

Si l'association parents/children est bi-directionnelle, contraintes


inutiles car automatiquement appliques par l'association 50

Contraintes de mariage

Pour tre mari, il faut avoir plus de 18 ans


Un homme est mari avec une femme et une femme avec un
homme
context Person inv:
(self.isMarried implies self.age >= 18 and
self.wife -> union(self.husband) -> size()=1)
and (self.wife -> notEmpty() implies
self.wife.gender =#female and
self.gender = #male and
self.wife.age >= 18 and
self.wife.isMarried = true and
self.wife.husband = self)
and (self.husband -> notEmpty() implies
self.husband.gender =#male and
self.gender = #female and
self.husband.age >= 18 and
self.husband.isMarried = true and
self.husband.wife = self)

51

Embauche d'un nouvel employ

Un employ qui est embauch n'appartenait pas dj la


compagnie
context Company::hireEmployee(p : Person)
pos t:
employee = employee@pre -> including(p)
employee@pre -> excludes(p) and
stockPrice() = stockPrice()@pre + 10

Equivalent
context Company::hireEmployee(p : Person)
pre: employee -> excludes(p)
pos t:
employee -> includes(p) and
stockPrice() = stockPrice()@pre + 10

52

Revenus selon l'age

Selon l'age de la personne, ses revenus sont

1% des revenus des parents quand elle est mineure


(argent de poche)
Ses salaires quand elle est majeure
context Person::income() : Real
pos t:
if age < 18 then
result = (parents.job.salary -> sum()) * 1%
els e
result = self.job.salary -> sum()
endif

53

Salaire pay :

Versement salaire

context Job::pay()
pos t:
account.balance = account.balance@pre + salary

Depuis OCL 2.0 : peut aussi prciser que l'opration deposit


doit tre appele

context Job::pay()
pos t: account^deposit(salary)
objet^operation(param1, ...) : renvoie vrai si un message
operation est envoy objet avec la liste de paramtres
prcise (si pas de valeur particulire : utilise ? : type)
Note

On s'loigne des principes d'OCL (langage de contraintes et


pas d'actions) et gnralement exprimable en UML avec
diagrammes d'interactions (squence, collaboration)
54

Vous aimerez peut-être aussi