• Aucun résultat trouvé

Demarche de conception

7.2.1 Problematique

Les classes formelles ranent les TAG en donnant une representation particuliere mais abstraite. Les operations deviennent des methodes, et les axiomes, s'ils existent sont groupes dans les methodes. Deux approches extr^emes sont possibles pour passer d'un type (abstrait) de donnees a une classe (formelle): la conception plate et la conception ordonnee.

Conceptionplate

En conceptionplate, une seule classe decrit le TAG. Si l'automate est represente par des

predicats d'etat ou une fonction de transition alors les preconditions des methodes sont cal- culables directement par l'algorithme de la section 5.4.3. Dans le cas contraire, le concepteur les exprime en fonction d'une structure abstraite qu'il aura degage. Supposons maintenant une structure abstraite quelconque. Puisque les observateurs peuvent ^etre partiels, certains selec- teurs de champ peuvent ne pas avoir de valeur a un instant donne. Nous utiliserons de preference un champ conditionnel a la valeur inde nie (nilou?) usuelle en programmation. Examinons

une conception plate et intuitive du TAGLiftpar la classe formelleFlatLift. FlatLift

inherits from OBJECT

comments: classe formelle de l'ascenseur Lift

param: Weightable

features: limits, bottomLevel, topLevel, level, capacity, weight,up, down, arrived, chgCapacity, getIn, getOut, getOOO, repaired, restart, stop, new, copy, isEqual, describe, install

aspect : lift

eld selectors constraint

bottomLevel : FlatLift ?! Integer

topLevel : FlatLift ?! Integer bottomLevel(Self) < topLevel(Self)

capacity : FlatLift ?! RealGt1 and

contents : FlatLift ?! Set[Weightable] 0 <= weight(Self)

isOnFloor : FlatLift ?! Boolean and

level : FlatLift ?! Integer bottomLevel(Self) <= level(Self) <=

requires: isOnFloor(Self) == true

isOverloaded : FlatLift ?! Boolean topLevel(Self)

requires: isOnFloor(Self) == true

isOnTop : FlatLift ?! Boolean and

requires: isOnFloor(Self) == true

isOnBottom : FlatLift ?! Boolean not(isOnTop(Self) and isOnBottom(Self))

requires: isOnFloor(Self) == true

isGoingUp : FlatLift ?! Boolean and

requires: isOnFloor(Self) == false

distance : FlatLift ?! IntegerGt1 bottomLevel(Self) <= distance(Self) <=

requires: isOnFloor(Self) == false

isStopped : FlatLift ?! Boolean topLevel(Self)

requires: isOnFloor(Self) == false isOutOfOrder : FlatLift ?! Boolean

extensions

;; limits : provides the lift limits (top and bottom levels) limits : FlatLift ?! Tuple(Integer Integer)

limits(Self) == newTuple(bottomLevel(Self), topLevel(Self)) ;; chgCapacity : set a new capacity for the lift

chgCapacity : FlatLift RealGt1 ?! FlatLift

var: Xcap : RealGt1

chgCapacity(Self, Xcap) == copy(Self, capacity = Xcap) ;; up : gets up Xd levels

up : FlatLift IntegerGt1 ?! FlatLift

var: Xd : IntegerGt1

isOnTop(Self) == false ==> up(Self, Xd) ==

FlatLift

extensions

;; down : gets down Xd levels

down : FlatLift IntegerGt1 ?! FlatLift

var: Xd : IntegerGt1

isOnBottom(Self) == false ==> down(Self, Xd) ==

copy(Self, isOnFloor = false, distance = Xd, isGoingUp = false) ;; arrived : the lift reaches the required level

arrived : FlatLift ?! FlatLift

isGoingUp(Self) == true ^(level(Self) + distance (Self) = topLevel(Self)) == true ==> arrived(Self) == copy(Self, isOnFloor = true, isOnBottom = false,

isOnTop = true, level = topLevel(Self))

isGoingUp(Self) == true ^(level(Self) + distance (Self) < topLevel(Self)) == true ==> arrived(Self) == copy(Self, isOnFloor = true, isOnBottom = false,

isOnTop = false, level = level(Self) + distance (Self))

isGoingUp(Self) == false ^(level(Self) - distance (Self) = bottomLevel(Self)) == true ==> arrived(Self) == copy(Self, isOnFloor = true, isOnBottom = true,

isOnTop = false, level = bottomLevel(Self))

isGoingUp(Self) == false ^(level(Self) - distance (Self) > bottomLevel(Self)) == true ==> arrived(Self) == copy(Self, isOnFloor = true, isOnBottom = false,

isOnTop = false, level = level(Self) - distance (Self)) ;; weight : provides the total weight the lift

weight : FlatLift ?! Real

weight(Self) == sum(contents(Self),weight) ;; getIn : a weightable gets inside the lift

getIn : FlatLift Weightable ?! FlatLift

var: Xw : Weightable

isOverloaded(Self) == false ^(weight(Self) + weight(Xw) <= capacity(Self)) == true ==> getIn(Self, Xw) == copy(Self, contents = contents + fweight(Xw)g)

isOverloaded(Self) == false ^(weight(Self) + weight(Xw) > capacity(Self)) == true ==>

getIn(Self, Xw) == copy(Self, contents = contents + fweight(Xw)g, isOverloaded = true) ;; isIn : indicates if the lift contains a weightable

isIn : FlatLift Weightable ?! Boolean

var: Xw : Weightable

isIn(Self,Xw) == belongsTo(contents(Self),Xw) ;; getOut : a weightable gets outside the cage

getOut : FlatLift Weightable ?! FlatLift

var: Xw : Weightable

isOverloaded(Self) == false ^isIn(Self,Xw) == true ==>

getOut(Self, Xw) == copy(Self, contents = contents - fXwg) isOverloaded(Self) == true ^isIn(Self,Xw) == true ^

(weight(Self) - weight(Xw) > capacity(Self)) == true ==> getOut(Self, Xw) == copy(Self, contents = contents - fXwg) isOverloaded(Self) == true ^isIn(Self,Xw) == true ^

(weight(Self) - weight(Xw) <= capacity(Self)) == true ==>

getOut(Self, Xw) == copy(Self, contents = contents - fXwg, isOverloaded = false) ;; stop : stops the lift

stop : FlatLift ?! FlatLift

isStopped(Self) == false ==> stop(Self) == copy(Self, isStopped = true) ;; restart : restarts the lift

restart : FlatLift ?! FlatLift

isStopped(Self) == true ==> restart(Self) == copy(Self, isStopped = false) ;; getOOO : the lift becomes out of order

getOOO : FlatLift ?! FlatLift

isOutOfOrder(Self) == false ==> getOOO(Self) == copy(Self, isOutOfOrder = true) ;; repaired : the lift is being repaired

repaired : FlatLift ?! FlatLift

isOutOfOrder(Self) == true ==> repaired(Self) ==

install(FlatLift, bottomLevel(Self), topLevel(Self), capacity(Self))

class methods

;; install : build an initial lift

install : Integer Integer RealGt1 ?! FlatLift

var: Xbot : Integer,Xtop: Integer,Xcap: RealGt1

install(Xbot, Xtop, Xcap) == newFlatLift(bottomLevel = Xbot, topLevel = Xtop, capacity = Xcap)

La conception d'une telle classe n'est pas triviale a partir du TAG. Les inconvenients de cette approche sont: descriptions souvent operationnelles, preconditions complexes, classes vo- lumineuses pas facile a lire, a comprendre et a specialiser.

Conceptionordonnee

En conceptionordonnee, un TAG est de ni par un schema. Rappelons qu'un schema est un

sous-ensemble du graphe d'heritage de racine unique une classe abstraite representant le type de donnees. Par defaut, le schema est initial , c'est-a-dire qu'il comporte deux niveaux: une racine et des feuilles appelees classes terminales. La racine est une classe abstraite correspondant au TAG. Les classes terminales representent les etats (le nom de la classe est la concatenation du nom du type et du nom de l'etat). Voici le schema initial du TAGLift.

MT BT MMU MMD BM TM MB TB BL ML TL BO MO TO

S2 S3 S4 S5 S6 S7 S8 S1

OOO

Lift

Figure 55 : Schema initial pour l'ascenseurLift

Cette representation est induite par la semantique algebrique des etats: un etat est un sous- type (une algebre) du type d'inter^et. Les selecteurs de champ sont des fonctions totales et les preconditions sont plus simples. Le partitionnement facilite la comprehension et la reutilisation mais risque d'entra^ner une explosion combinatoire du nombre de classes avec duplication de methodes identiques (celles des operations applicables a plusieurs etats) : pas de partage de code tant qu'on n'introduit pas des classes abstraites intermediaires. Un autre inconvenient im- portant est la mediocre representation en termes d'objet qui conduit a de l'heritage dynamique, c'est-a-dire qu'un objet est instance de di erentes classes au cours de son existence.

7.2.2 Strategie de conception

Nous souhaitons une approche plus ne que la conception plate et plus ecace que la conception ordonnee ci-dessus. Cette approche intermediaire est resumee dans la gure suivante.

joindre les sous-classes d’une super- classe commune aux classes abstraites étendre la hiérarchie classCB classCC state5 ... TAG abstrait

état 1 état 2 état 3 état 4 ... état n

classeA classeB classeC

AA A1 CB CC

état1 état2 état3 état4 état5 ...

schéma initial d’héritage

grouper les états fortement couplés

schéma structuré

schéma restructuré

Classe abstraite TAG

Classe abstraite TAG

classeA classeB classeC

restructuration construction

initial du schéma

L'idee est de partir du schema initial, de le factoriser puis de le structurer a n de mettre en evidence les comportements communs dans des classes abstraites intermediaires et en n de factoriser les sous-classes d'une super-classe pour optimiser la representation. Les classes terminales sont regroupees soit parce qu'elles ont un comportement tres proche (reduction ver- ticale) soit parce que les etats dont elles sont issues sont fortement lies (reduction horizontale). Nous suivons en cela les principes habituels de la conception modulaire: reduction du couplage modulaire, renforcement de la coherence modulaire.

Cette approche est adaptee aux TAG complexes tels que l'ascenseur de la gure 79. Par restructuration successive, le schema est parfois reduit a une seule classe. Ce qui constitue une demarche rigoureuse pour atteindre la conception plate.

Nous proposons donc une methode de ranement des TAG en classes formelles en trois etapes principales: (1) extraire un schema d'heritage a partir du graphe de comportement dynamique, (2) restructurer et regrouper les classes formelles, (3) ecrire les extensions.

USE et CREATE schémas restructuration des axiomes écriture construction du schéma TAG cation TAG spécifi- réduit TAG générateur initial des CF complet des CF schéma schéma Sélection d’un ensemble d’opé-

rations primitives éclatement/union des profils détermination d’une structure abstraite restructuration des classes et des schémas écriture des méthodes secondaires implantation l’automate Réduction de structuré

Figure 57 : Cycle de ranement Les sections suivantes decrivent les trois etapes de la demarche.