• Aucun résultat trouvé

Soient C l'ensemble des classes et métaclasses de SHOOD, I l'ensemble des instances terminales représentant les données de la base de connaissances, sachant que toute instance de I est rattachée à une ou de plusieurs classes de C.

8.1.1 Définition d'une opération

Une opération est une application sur l'ensemble C (de C vers C) représentant une évolution de classes, ou sur l'ensemble I représentant une évolution d'instances. L’ensemble des opérations est constitué de fonctions de création, de suppression et de modification de C et de I. Cet ensemble est noté O ; une opération o de O décrit la nature de l’évolution, c’est-à-dire une création, une suppression, etc. et sur quoi s'exécute o (attribut, classe, instance).

Pour qu'une exécution d'une opération de O n'introduise pas d'incohérence, il est nécessaire, dans certains cas, d'effectuer des contrôles ou vérifications pour rejeter ou accepter l’opération. Dans d'autres cas, le système doit réagir en conséquence à cette évolution par des propagations de mise à jour, toujours pour maintenir les informations cohérentes.

Ces vérifications et propagations devront avoir lieu respectivement avant et après l'exécution de l'opération qui sont illustrées par les exemples suivants :

D

D

(par exemple : redéfinir le domaine des attributs ayant cette classe pour domaine),

• pour l'ajout d'un attribut dans une classe, les vérifications et les propagations peuvent avoir lieu après l'héritage de l'attribut ; ceci évite de simuler l'héritage pour détecter des incompatibilités de types.

Dans cet exemple, l'ajout de l'attribut at dans la classe B peut introduire une incompatibilité si l'intersection de T2 et de T1 est vide. Si le calcul T1 inter T2 est vide, l'ajout de l’attribut at sera défait.

Nous constatons par ces exemples qu’une opération doit être précédée et suivie d’une condition appelé vérification. De même, elle doit être précédée et suivie d’une action repésentant la propagation à effectuer. Nous proposons de fusionner syntaxiquement ces deux traitements, et comme les vérifications doivent être exécutées avant les propagations, une opération sera alors précédée d’un traitement appelé pré-opération et suivie d’un traitement appelé post-opération, chacun assurant la vérification puis la propagation (Figure 8-1).

Pré-condition Opération Post-condition Et Pré-opération (condition-action) Opération Post-opération (condition-action) Pré-action Opération Post-action Pré-condition Pré-action Opération Post-condition Post-action On fusionne On factorise Vérifications Propagations

Figure 8-1 :Exécution d’une opération

8.1.2 Définition d'une pré-opération

Une pré-opération est un traitement effectué avant l'exécution de l'opération. Elle est

Classe A at : T1 Classe B at : T2 Classe C at : T1 inter T2 Spécialisation

l'opération. Si la condition d'une pré-opération est insatisfaite, l'opération est interrompue. Notons Pré l'ensemble des pré-opérations.

Exemple :

Pré-op : Condition = Teste si une classe possède des instances Action = Tout attribut ayant pour domaine cette classe aura pour domaine une super-classe de la classe supprimée Op : Supprimer une classe

8.1.3 Définition d'une post-opération

Une post-opération est un traitement effectué après l'exécution de l'opération. De même que pour la pré-opération, une post-opération est constituée d'un couple condition-action. Si

condition est insatisfaite l'exécution de l'opération et de la pré-opération sont défaites. Dans le

cas contraire, action permet de propager les conséquences dues à l'exécution de l'opération. Notons Post l'ensemble des post-opérations.

Exemple :

Op :Ajouter un attribut

Post-op : Condition = Tester si une intersection d'attribut n'est pas vide Action = Répercuter l'ajout sur les instances.

8.1.4 Définition d'une règle d'évolution

Chaque cas d'évolution est exprimé par une règle d'évolution. Les règles d'évolution de schémas et d’instances vont conduire le programmeur ou le concepteur à préciser les répercussions caractérisant une évolution et les conditions qui la contraignent.

Une règle d'évolution r est un triplet < pré-o, o, post-o > tel que : pré-o ∈ Pré, o ∈ Ο et post-o ∈ Post. La règle r décrit de manière déclarative une sémantique d'évolution d’un concept. En d'autres termes, elle exprime les réactions du système à l'exécution de l'opération o. L'exécution de o entraîne l'évaluation de la pré-opération pré-o : si sa condition est satisfaite, alors son action est exécutée, ainsi que l'opération o. La condition de post-o est évaluée après l'exécution de o, et si celle-ci n’est pas vérifiée, les exécutions de o et de pré-o sont défaites. Dans le cas contraire (aucune incohérence n'a été détectée), l'action de post-o est exécutée pour propager les conséquences de l'exécution de o. Notons R l’ensemble des règles d’évolution.

o : Supprimer_classe

Pré-o : Condition = Teste si une classe possède des instances Action = Tout attribut ayant pour domaine cette classe aura pour domaine une super-classe de la classe supprimée Post-o : Condition = aucune

Action = Envoyer un message (" la suppression de la classe est terminée").

Si on demande la suppression de classe (appel de o), le système vérifiera d'abord la condition de la pré-opération. Si la classe ne possède pas d'instances, la classe pourra être supprimée. Mais avant la suppression, les domaines d'attribut référençant cette classe sont modifiés par une super-classe commune. Après la suppression, un message de fin de suppression (post-opération) est envoyé.

8.1.5 Définition d'une stratégie

Ce concept a été introduit pour permettre la gestion de plusieurs stratégies d’évolution. Une stratégie représente l’ensemble des sémantiques d’évolution d’une application ou des concepts d’un modèle de données. Elle est modélisée par l'ensemble des règles d'évolution traduisant cette stratégie d'évolution. Nous offrons, par ce concept, la possibilité de faire coexister plusieurs schémas d’évolution dont un seul sera pris en compte par le système à un instant donné. Nous offrons de même la possibilité de réutiliser un schéma d’évolution pour en créer d’autres.

Nous définissons une stratégie comme un ensemble de règles d’évolution de R. Notons S l’ensemble des stratégies. Toute stratégie si ∈ S est composée d’un sous-ensemble Ri de R. Soient deux règles d'évolution (r1, r2) telles que :

r1 = <o1, pré1, post1> définit une sémantique de l'opération o1 avec r1 ∈ R1, et

r2 = <o1, pré2, post2> définit une autre sémantique de l'opération o1 avec r2 ∈ R. r1 et r2 définissent deux règles d'évolution "disjointes" (elles ne peuvent pas appartenir à une même stratégie) ; lors de l'exécution de o1, on doit évaluer soit r1, soit r2. Nous proposons alors de définir une deuxième stratégie qui redéfinit r1 par r2. La définition d’une stratégie devient alors :

soient s1 et s2 ∈ S, avec s1 et s2 composées respectivement de R1 et R2, et s2 redéfinit s1 : r1 ∈ R1 et ∃ r2 ∈ R2/ r2 redéfinit r1 ==> R2 = R1-{r1} ∪ {r2}.

Le programmeur choisit toujours une et une seule stratégie de S et lors de l'exécution d'une opération, la règle correspondant à la stratégie choisie sera évaluée.

Exemple :

soient r1 et r2 deux règles d'évolution : r1 : o= supprimer une classe

pré-o = vérifier que la classe ne possède pas d'instances

r2 : o= supprimer une classe

pré-o = supprimer les instances de cette classe

Comme ces deux règles sont disjointes, elles pourront appartenir à deux stratégies différentes. En phase d'exécution, seulement une des deux règles doit être évaluée.

Ne possédant pas de moyen de vérifier la disjonction de deux règles, il est impossible de vérifier la cohérence d’une stratégie. En effet, en présence de deux règles d’évolution pour une même opération, il n’est pas possible de dire si deux règles sont contradictoires ou complémentaires. De même, la complétude d’une stratégie ne peut être vérifiée car le nombre de règles nécessaires pour exprimer la sémantique complète d’une opération d’évolution n’est pas connu. Actuellement, la vérification de la consistence des règles d’évolution est à la charge de celui qui les spécifient.

Par la suite, nous présentons l’utilisation de ces concepts à travers un langage de commandes, permettant de décrire l’évolution d’une classe ou d’une instance.