Vous êtes sur la page 1sur 49

INF3143

Modélisation et spécification
formelles des logiciels

Hiver 2017

Alexandre Terrasa
Département d’informatique, UQÀM
OCL
Travailler avec les classes

2
Appels statiques
Appeler une méthode statique sur une classe

context Etudiant::permaCode: String


init: Etudiant::uniqueCode()

3
Opération sur les classes
Obtenir l’ensemble de toutes les instances
d’une classe ou interface
Classe.allInstances(): Set(T)

Exemple:
context Etudiant

inv: Etudiant.allInstances()->includes(self)
4
Exercice 6
Tournoi
date: Date tournoi
pro: Boolean
1
tournois *

affronte
équipes matchs *
* *
Joueur Équipe Match
victoire: Boolean
nom: String joueurs équipe nom: String
pro: Boolean
age: Integer
1..5 1 5
*
Exercice 6
Contraintes:
● Deux tournois ne peuvent se dérouler à la
même date
● Deux joueurs du même âge ne peuvent
avoir le même nom

6
Solution 6
context Tournoi
inv: Tournoi.allInstances()->forAll(t1, t2 |
t1 <> t2 implies t1.date <> t2.date)

context Joueur
inv: Joueur.allInstances()->forAll(t1, t2 |
t1 <> t2 and t1.age = t2.age implies
t1.nom <> t2.nom)

7
Opération oclIsNew
Vérifier la création d’une instance
post: object.oclIsNew()
vrai si et seulement si object n’existait pas
dans la pré-condition

context Particule::creerParticule(): Particule

post: result.oclIsNew()
8
Rappels sur l’héritage

9
Rappel: héritage
Concept de la programmation orientée objet
● code découpée en classes
● les classes filles héritent des propriétés
de leurs classes mères
Permet
● réutilisation de code
● sous-typage
● polymorphisme
10
Propriétés de l’héritage
La relation d’héritage est
● transitive
● non-réflexive
● non-symétrique
● sans cycle

11
Relation transitive
Si B hérite de A et C hérite de Ovipare

B alors C hérite de A pondre()

Oiseau
Ainsi
voler()

● Canard est un Oiseau et


aussi un Ovipare Canard
● Canard hérite des
cancaner()
propriétés pondre et voler 12
Relation non-réflexive
Une classe ne peut pas hériter d’elle même

x
Canard

cancaner()

13
Relation non-symétrique
Si A hérite de B alors B n’hérite pas de A

Oiseau

voler()
● Tous les canards sont
des oiseaux
x ● Tous les oiseaux ne
sont pas forcément des
Canard
canards
cancaner()
14
Relation sans cycle
Si B hérite de A et C hérite Ovipare

de B alors A ne peut pas pondre()

hériter de C
Oiseau

x voler()

Canard

cancaner()
15
Principe de substitution de
Liskov

“Si S est un sous-type de T, alors tout objet de


type T peut être remplacé par un objet de type S”

- B. Liskov et J. Wing
Family Values: A Behavioral Notion of Subtyping, 1993

16
Exemple de substitualité

Arme

Guerrier

équiper(Arme arme)

Épée Hache

17
Exemple de substitualité
class Guerrier {
void équiper(Arme arme) { /* … */ }
}

Guerrier g = new Guerrier()


g.équiper(new Épée()) // OK: Épée <: Arme
g.équiper(new Hache()) // OK: Hache <: Arme
g.équiper(new Canard()) // KO: Canard !<: Arme

18
Spécialisation et redéfinition
Une classe
● hérite des propriétés des classes qu’elle
spécialise
● peut étendre ses super-classes en
○ ajoutant de nouvelles propriétés
○ redéfinissant les propriétés héritées

19
Sous-typage
Une classe = Un type (mais pas toujours)
● définition des types de données
● utilisation dans les signatures
Type et héritage
● Si B hérite de A, alors B est un sous-type
de A
● sous-typage = mêmes principes que la
relation d’héritage 20
Restrictions du principe de Liskov

Restrictions sur les signatures des méthodes


● contravariance des arguments
● covariance du type de retour
● invariance des attributs

⇒ Pour assurer un typage cohérent et sûr

21
Héritage et variance des types

Idée
● changer le type des Animal
arguments et des types de
manger(n: Nourriture)
retour dans les
redéfinitions
Vache

manger(n: TYPE?)
Questions
● est-ce possible?
● selon quelles contraintes? 22
Notion de variance
Mangeable
Soit n: T avec T = Nourriture
● T varie dans le même sens
que la hiérarchie des types
○ T = Herbe Nourriture

○ Covariance
● T varie dans le sens inverse
de la hiérarchie des types
○ T = Mangeable Herbe
○ Contravariance
23
Variance des arguments

Règle pour un typage sûr


● Redéfinition contravariante des
arguments des méthodes
Exemple: Eiffel

Note: l’invariance marche aussi…


Exemples: C++, Java, Scala, C#, D 24
Exemple de la vache folle
Pourquoi la redéfinition
covariante des arguments est
non-sûre?
Animal Nourriture

manger(n: Nourriture)

Vache Herbe

manger(n: Herbe) 25
Exemple de la vache folle
Pourquoi la redéfinition
covariante des arguments est
non-sûre?
Animal Nourriture

manger(n: Nourriture)

Vache Herbe

manger(n: Herbe) 26
Exemple de la vache folle
Vache v = new Vache()
v.manger(new Herbe()) // OK
v.manger(new Vache()) // Refusé

27
Exemple de la vache folle
Vache v = new Vache()
v.manger(new Herbe()) // OK
v.manger(new Vache()) // Refusé

Animal a = new Vache()


a.manger(new Herbe()) // OK
a.manger(new Vache()) // Vache folle

28
Variance du type de retour
Règle pour un typage sûr
● Redéfinition covariante des types de
retour des méthodes
Exemples: C++, Java, Scala, D, Eiffel
Note: l’invariance marche aussi…
Exemple: C#

29
Exemple du distributeur
Pourquoi la redéfinition contravariante des
types de retour est-elle non-sûre?

Distributeur Nourriture

distribuer: Herbe

Vache Distributeur2 Herbe

manger(n: Herbe) distribuer: Nourriture 30


Exemple du distributeur
Vache v = new Vache()

Distributeur d = new Distributeur()


v.manger(d.distribuer())
// La vache mange de l’herbe OK

d = new Distributeur2()
v.manger(d.distribuer())
// La vache mange autre chose que de l’herbe

31
Variance des attributs
Pour un attribut foo: T
● setFoo(foo: T)
○ contravariance des types des arguments
● getFoo(): T
○ covariance des types de retour

⇒ Invariance des attributs


32
Substitualité en Java
Méthodes
● invariance des paramètres
● covariance des types de retour
Attributs
● invariance des attributs (via masquage)

Exemples: https://github.com/Morriar/INF3143_variance 33
OCL
Typage

34
Types OCL primitifs
Boolean true, false
Integer 1 ; -3 ; 12 ; 42
Real 1,5 ; 3,14 ; -10.3
String ‘Hello World!’
OCLVoid null ; invalid

35
Collections
OCL définit 4 types de collections
● Set
● OrderedSet
● Bag
● Séquence

Toutes ces classes sont des sous-types du


types abstrait Collection. 36
Type invalide OclInvalid
Retourné quand une partie de l’expression est
invalide:
● 10 + ‘foo’
● 23 * false
● sequence_vide->first()

37
Propagation des invalides
Une valeur invalide se propage dans toute
l’expression sauf exception:
● true or invalid = true
● false and invalid = false
● false implies invalid = true
● invalid implies true = true

38
Type d’un objet
Vérifier le type dynamique d’un objet
● exactement du type Type
object.oclIsTypeOf(Type)
● un sous-type du type Type
object.oclIsKindOf(Type)

39
Transtypage
Changer le type statique d’un objet
object.oclAsType(Type2)

● pour accéder à une propriété d’un autre


type que celui de object
● retourne invalid si object n’est pas un
sous-type de Type2 à l’exécution.
40
Collections et typage
Si T1 <: T2 (T1 est sous-type de T2)
● Set(T1) <: Collection(T2)
● Sequence(T1) <: Collection(T2)
● Bag(T1) <: Collection(T2)
● OrderedSet(T1) <: Collection(T2)

41
Transtypage et collections
Changer le type statique d’une collection
collection->oclAsType(Set(String))
Changer le type statique des éléments
collection->collect(oclAsType(String))
Sélectionner les éléments d’un certain type
collection->selectByKind(Etudiant)
42
Principe de substitution
Tout ce qui s’applique à un animal s’applique
aussi à une vache.

OCL suit le principe de substitution de Liskov


Les méthodes qui utilisent des objets d’une
classe doivent pouvoir utiliser des objets
dérivés de cette classe sans même le savoir.
43
Substitution et invariants
Principe de substitution sur les invariants
● les invariants sont toujours hérités par les
sous-classes
● les invariants peuvent être renforcés dans
les sous-classes

44
Substitution et conditions
Principe de substitution sur les conditions
● les pré-conditions peuvent seulement être
assouplies (contravariance)
● les post-conditions peuvent seulement
être renforcées (covariance)

45
Exemple
Pré-condition covariante invalide
L’exemple est invalide, expliquez pourquoi?

context Animal::mange(nourriture: Nourriture)

pre: nourriture.oclIsKindOf(Nourriture)

context Vache::mange(nourriture: Nourriture)

pre: nourriture.oclIsKindOf(Herbe)
46
Solution
List<Animaux> arche = new ArrayList<Animal>();
arche.add(new Vache()) // Vache <: Animal, OK
nourrir_au_grain(arche)

void nourrir_au_grain(animaux: List<Animal>) {


for(Animal animal : animaux) {
animal.manger(new Grain); // Grain <: Nourriture, OK
} // La Vache va manger du grain et la pré-condition explose
}

47
Conclusion

OCL
● Permet d’accéder aux instances d’une
classe
○ allInstances()
● Permet de travailler avec les types du
modèle
○ oclIsTypeOf(), oclIsKindOf(), oclAsKindOf()

Le typage implique des contraintes


48
Ressources
● http://www.omg.org/spec/OCL/
● http://laurent-audibert.developpez.com/Cours-
UML/?page=object-constraint-langage-ocl
● Tremblay, G - Modélisation et spécification
formelle de logiciels - Loze-Dion Editeurs
Inc., 2004 (chap 12)

49

Vous aimerez peut-être aussi