Object Constraint Language (OCL) Une introduction Master 2 IFPRU - Module Ingén

Object Constraint Language (OCL) Une introduction Master 2 IFPRU - Module Ingénierie des modèles - FMIN310 Marianne Huchard 7 novembre 2008 1 Présentation générale OCL est un langage formel, basé sur la logique des prédicats du pre- mier ordre, pour annoter les diagrammes UML en permettant notamment l’expression de contraintes. 1.1 Objectif du langage Voici les arguments avancés pour l’introduction d’OCL. – Accompagner les diagrammes UML de descriptions : – précises – non ambiguës – Eviter cependant les désavantages des langages formels traditionnels qui sont peu utilisables par les utilisateurs et les concepteurs qui ne sont pas rompus à l’exercice des mathématiques : – rester facile à écrire ... – et facile à lire Dans le cadre de l’ingénierie des modèles, la précision du langage OCL est nécessaire pour pouvoir traduire automatiquement les contraintes OCL dans un langage de programmation afin de les vérifier pendant l’exécution d’un programme. 1.2 Historique OCL s’inspire de Syntropy [CD94] méthode basée sur une combinaison d’OMT (Object Modeling Technique) [RBE+97] et d’un sous-ensemble de Z. A l’origine, OCL a été développé en 1997 par Jos Warmer (IBM), sur les bases du langage IBEL (Integrated Business Engineering Language). Il a été formellement intégré à UML 1.1 en 1999. Nous présentons dans ce document OCL tel qu’il est proposé dans la version UML 2.0 [OMG03a]. Vous trouverez dans [MG00] une présentation d’OCL (UML 1.4) qui a servi de base à la réalisation de ce support de cours, et dans [Nyt] quelques exemples complémentaires. 1 1.3 Principe La notion de contrainte Une contrainte est une expression à valeur boo- léenne que l’on peut attacher à n’importe quel élément UML. Elle indique en général une restriction ou donne des informations com- plémentaires sur un modèle. Langage déclaratif Les contraintes ne sont pas opérationnelles. On ne peut pas invoquer de processus ni d’opérations autres que des requêtes. On ne décrit pas le comportement à adopter si une contrainte n’est pas respectée. Langage sans effet de bord Les instances ne sont pas modifiées par les contraintes. 1.4 Utilisation Les contraintes servent dans plusieurs situations : – description d’invariants sur les classes et les types – pré-conditions et post-conditions sur les opérations et méthodes – contraintes sur la valeur retournée par une opération ou une méthode – règles de dérivation des attributs – description de cibles pour les messages et les actions – expression des gardes (conditions dans les diagrammes dynamiques) – invariants de type pour les stéréotypes Les contraintes servent en particulier à décrire la sémantique d’UML ou de ses diverses extensions, en participant à la définition des profils. 2 La notion de contexte Une contrainte OCL est liée à un contexte, qui est le type, l’opération ou l’attribut auquel la contrainte se rapporte. context monContexte <stéréotype> : Expression de la contrainte Personne − age : entier + setAge(in a : entier) + getAge():entier {query} − /majeur : booléen Fig. 1 – Une classe Personne Le stéréotype peut prendre les valeurs suivantes : – inv invariant de classe – pre précondition – post postcondition – body indique le résultat d’une opération query 2 – init indique la valeur initiale d’un attribut – derive indique la valeur dérivée d’un attribut Par exemple, on peut définir les contraintes suivantes dans le contexte de la classe Personne de la figure 1, puis dans le contexte de ses méthodes setAge, getAge et pour son attribut age. context Personne inv : (age <= 140) and (age >=0) - - l’âge est compris entre 0 et 140 ans On peut placer des commentaires dans les expressions OCL, ils débutent par deux tirets et se prolongent jusqu’à la fin de la ligne. context Personne::setAge(a :entier) pre : (a <= 140) and (a >=0) and (a >= age) post : age = a – on peut écrire également a=age context Personne::getAge() :entier body : age context Personne::age :entier init : 0 context Personne::majeur :booléen derive : age>=18 Version visuelle La figure 2 présente une version alternative, graphique, de la contrainte sur l’âge de la personne. Personne − age : entier + setAge(in a : entier) {<<invariant>> (age<=140 and age >=0) } Fig. 2 – Une classe Personne Nommage de la contrainte context Personne inv ageBorné : (age <= 140) and (age >=0) - - l’âge ne peut depasser 140 ans Utilisation du mot-clef self pour désigner l’objet Notez le caractère . qui offre la navigation (accès) à l’attribut. context Personne inv : (self.age <= 140) and (self.age >=0) - - l’âge ne peut depasser 140 ans 3 Utilisation d’un nom d’instance formel context p :Personne inv : (p.age <= 140) and (p.age >=0) - - l’age ne peut depasser 140 ans Question 2.1 Ajoutez un attribut mère de type Personne dans la classe Personne. Ecrivez une contrainte précisant que la mère d’une personne ne peut être cette personne elle-même et que l’âge de la mère doit être supérieur à celui de la personne. Réponse 2.1 context Personne inv : self.mère <> self and self.mère.age > self.age 3 Types OCL La figure 3 présente la hiérarchie des types en OCL. Nous les décrirons progressivement dans cette section et dans les suivantes. OclAny Réel Booléen String du modèle Collection OclState OclVoid types de base prédéfinis Entier OclType OclModelElement types et éléments Tuple Bag Sequence OrderedSet Set ............ Fig. 3 – La hiérarchie des types en OCL 3.1 Types de base Les types de base prédéfinis sont les suivants. – Entier (Integer) – Réel (Real) – String – Booléen (Boolean) Quelques types spéciaux s’y ajoutent, en particulier : – OclModelElement (énumération des éléments du modèle) – OclType (énumération des types du modèle) – OclAny (tout type autre que Tuple et Collection) – OclState (pour les diagrammes d’états) – OclVoid sous-type de tous les types 4 Entier opérateurs = <> + - * / abs div mod max min < > <= >= - est unaire ou binaire Réel opérateurs = <> + - * / abs floor round max min < > <= >= - est unaire ou binaire String opérateurs = size() concat(String) toUpper() toLower() substring(Entier, Entier) Les chaînes de caractères constantes s’écrivent entre deux simples quotes : ’voici une chaîne’ Booléen opérateurs = or xor and not b1 implies b2 if b then expression1 else expression2 endif Quelques exemples d’utilisation des opérateurs booléens, sur la figure 4. − age : entier − majeur : Booléen − marié : Booléen − catégorie : enum {enfant,ado,adulte} Personne Fig. 4 – La classe Personne précisée context Personne inv : marié implies majeur context Personne inv : if age >=18 then majeur=vrai else majeur=faux endif Cette dernière contrainte peut être plus concise (nous l’avons même déjà écrite avec derive) : context Personne inv : majeur = age >=18 5 précédence des opérateurs . -> not - unaire * / + - if then else < > <= >= <> = and or xor implies 3.2 Types énumérés Leurs valeurs apparaissent précédées de #. Par exemple, pour donner un invariant supplémentaire pour la figure 4, nous pourrions écrire : context Personne inv : if age <=12 then catégorie =#enfant else if age <=18 then catégorie =#ado else catégorie=#adulte endif endif Cet invariant peut aussi s’écrire avec derive. 3.3 Types des modèles Les types des modèles utilisables en OCL sont les « classificateurs », notamment les classes, les interfaces et les associations. On peut écrire en particulier des expressions impliquant des objets dont les types sont reliés par une relation de spécialisation, grâce aux opérateurs : – oclAsType(t) (conversion ascendante ou descendante de type vers t) ; la conversion ascendante sert pour l’accès à une propriété redéfinie ; la conversion descendante sert pour l’accès à une nouvelle propriété. – oclIsTypeOf(t) (vrai si t est supertype direct) – oclIsKindOf(t) (vrai si t est supertype indirect) Dans le cadre de la figure 5, nous pourrions écrire par exemple les ex- pressions (r est supposé désigner une instance de Rectangle) : – p = r – p.oclAsType(Rectangle) – r.oclIsTypeOf(Rectangle) (vrai) – r.oclIsKindOf(Polygone) (vrai) Question 3.1 En supposant l’existence d’un attribut hauteur dans la classe Rectangle et d’une méthode hauteur() :Réel dans Polygone, écrivez une contrainte dans Polygone disant que le résultat de hauteur() :Réel vaut hauteur pour les polygones qui sont des rectangles, sinon 0. Remarquez que c’est un exemple de mauvaise conception objet mais une excellente illustra- tion des opérateurs présentés ci-dessus ! 6 Polygone Rectangle p : Polygone r : Rectangle Fig. 5 – Polygones et rectangles Réponse 3.1 context Polygone::hauteur() post : if self.oclIsKindOf(Rectangle) then result=self.oclAsType(Rectangle).hauteur else result=0 endif 4 Navigation dans les modèles 4.1 Accès aux attributs L’accès (navigation) vers un attribut s’effectue en mentionnant l’attribut, comme nous l’avons déjà vu, derrière l’opérateur d’accès noté ’.’ Personne − age : Entier + getAge():Entier{query} Voiture − propriétaire : Personne Fig. 6 – Personnes et voitures Pour la classe Voiture de la figure 6, on peut ainsi écrire la contrainte ci-dessous. context Voiture inv propriétaireMajeur : self.propriétaire.age >= 18 Question 4.1 Ecrivez pour le diagramme de la figure 7 la contrainte qui caractérise l’attribut dérivé carteVermeil. Un uploads/Voyage/ cours-ocl20 1 .pdf

  • 23
  • 0
  • 0
Afficher les détails des licences
Licence et utilisation
Gratuit pour un usage personnel Attribution requise
Partager
  • Détails
  • Publié le Mar 19, 2022
  • Catégorie Travel / Voayage
  • Langue French
  • Taille du fichier 0.4117MB