23
Chapitre 11 Cours B4: Programmation et Développement 00 1/23 Version 1.0 Programmation et Développement orientés objets Cours B4 Chapitre 11: ETUDE DE CAS* Conception Détaillée * Extrait du livre « UML en ACTION » Pascal ROQUES et Franck VALLEE Editeur EYROLLES ISBN 2-212-09127-3

Programmation et Développement orientés objetssuffi.free.fr/poo/11-Exemple_UML6.pdf · 17/06/2001 Chapitre 11: Conception Détaillée 2/17 ... savoir appliquer le micro-processus

  • Upload
    buihanh

  • View
    217

  • Download
    0

Embed Size (px)

Citation preview

Chapitre 11 Cours B4: Programmation et Développement 00 1/23

Version 1.0

Programmation et Développement orientés objets

Cours B4Chapitre 11: ETUDE DE CAS*

Conception Détaillée

* Extrait du livre « UML en ACTION »Pascal ROQUES et Franck VALLEEEditeur EYROLLESISBN 2-212-09127-3

Chapitre 11 Cours B4: Programmation et Développement 00 2/23

17/06/2001 Chapitre 11: Conception Détaillée 2/17

Conception détailléeDernière étape de la modèlisationRaffinement du modèle logique pour documenter

les classesLes interfacesLes méthodesEt les tables

Elle s’appuie sur les frameworks techniques et regroupements « métier »Elle donne une image prête à coder du système

Nous arrivons maintenant à la phase ultime de modélisation avec UML. Après la modélisation des besoins puis l'organisation de la structure de la solution, la conception détaillée consiste à construire et à documenter précisément les classes, les interfaces, les tables et les méthodes qui constituent le codage de la solution. Il s'agit de : comprendre le rôle d'UML pour la conception détaillée; savoir appliquer le micro-processus utilisé pour bâtir une conception objet avec UML ; apprendre à construire une solution pour : la couche de présentation, la couche d'application et la couche métier distribuée ; La conception détaillée est essentiellement l’affinement du modèle logique décrit pendant la conception préliminaire. Il est ainsi possible de confier les catégories à des personnes différentes, qui pourront travailler indépendamment les unes des autres. La conception détaillée s'appuie donc sur les catégories de conception organisées à la fois suivant les frameworks techniques et les regroupements propres au métier. Les concepteurs construisent alors les classes, les vues d'IHM les interfaces, les tables et les méthodes qui vont donner une image « prête à coder » de la solution. En dernier lieu, il convient de préciser le contenu des sous-systèmes de manière à compléter la configuration logicielle.

Chapitre 11 Cours B4: Programmation et Développement 00 3/23

Le niveau d'abstraction visé par l'étape de conception détaillée est la conception des composants. II s'agit d'avoir une idée la plus précise possible pour la fabrication et l'assemblage des sous-systèmes de configuration logicielle. La conception détaillée précède la phase de codage. À ce niveau, toutes les questions relatives à l'agencement et aux détails de la solution doivent être modélisées. Ainsi, les interrogations restantes concernent exclusivement la bonne utilisation des langages et des outils de développement.

Chapitre 11 Cours B4: Programmation et Développement 00 4/23

17/06/2001 Chapitre 11: Conception Détaillée 3/17

Micro-processus de conception logique

Activité centrée sur le modèle logiqueDiagrammes de classe -> Préciser les structures des classes de développementDiagrammes de collaboration -> Préciser les collaborations entre objetsDiagrammes d’activités -> Exprimer les algorithmes des méthodes

Micro processusConcevoir les classesConcevoir les associationsConcevoir les attributsConcevoir les opérationsValider le modèle

Le micro-processus de conception logique concerne la définition des classes à implémenter. C'est donc une activité centrée sur le modèle logique, qui combine les diagrammes UML suivants: principalement les diagrammes de classes pour préciser la structure des classes de développement, mais aussi les diagrammes d'interactions pour préciser les collaborations entre objets, et les diagrammes d'activités pour exprimer les algorithmes des méthodes (il est possible de recourir à du pseudo-code pour les algorithmes les plus complexes. Il s'agit en fait d'esquisser le code des méthodes à développer. On peut utiliser un formalisme proche du langage utilisé pour le développement). Concevoir les classes consiste à transformer des concepts provenant de l'analyse, tels que les métaclasses ou les classes à états parallèles, en techniques disponibles, avec les langages et les outils de développement. Concevoir les associations définit la façon d'exploiter chaque association et les techniques qui seront employées dans le codage. Concevoir les attributs nécessite essentiellement d'identifier les structures de données, les itérations et d'autres types complexes permettant de représenter les attributs d'analyse avec le langage utilisé.

Chapitre 11 Cours B4: Programmation et Développement 00 5/23

Concevoir les opérations permet de déterminer le contenu des méthodes complexes et d'identifier en cascade de nouvelles classes et opérations dans la catégorie. Valider le modèle constitue la phase de décision du cycle itératif. Sortir de ce cycle signifie que le modèle donne l'image prête-à-coder de ses composants de configuration logicielle.

Chapitre 11 Cours B4: Programmation et Développement 00 6/23

17/06/2001 Chapitre 11: Conception Détaillée 4/17

Conception des classesMettre en adéquation les classes issues de l’analyse avec les possibilité du langage cibleIntroduire de nouvelles classes pour prendre en charge des responsabilité techniques -> design patternDistribuer les évènements et les messages sur les couches de conception

Les classes qui proviennent de l'analyse ne sont pas toujours conformes aux possibilités du langage d'implémentation. Dans certains cas, une analyse orientée objet est réalisée dans un langage non objet. La transformation des classes en codage est alors particulièrement importante pour conserver la trace du passage de l'analyse au code. Java ou C++ offrent bien entendu une transformation beaucoup plus directe. Certaines formes telles que les métaclasses, les états ou les héritages multiples sont cependant tolérées par les analystes mais inconnues de Java. Concevoir les classes consiste tout d'abord à expliciter comment ces concepts devront être traduits dans le code. Concevoir les classes, c'est aussi en introduire de nouvelles soit pour prendre en charge des responsabilités purement techniques, soit pour décharger une classe d'analyse de certains de ces aspects techniques. Les liens qui rattachent ces classes entre elles doivent le plus souvent correspondre à des design patterns. On trouvera à terme des classes comme des « fabriques », des « archiveurs », des « traceurs », des « vérificateurs de cohérence », etc. Concevoir les classes, c'est enfin redistribuer les messages et les événements du modèle dynamique sur les différentes couches de conception. Il est probable en effet que ces concepts vus de manière abstraite par l'analyste ne correspondent plus aux principes de conception. Pour les systèmes client/serveur, nous pensons plus particulièrement à la redistribution des échanges entre les couches métier et application. Ces échanges s'appuyant sur les capacités d'un réseau physique

Chapitre 11 Cours B4: Programmation et Développement 00 7/23

doivent faire l'objet d'optimisations. Dans cette optique, il convient que les diagrammes d'états soient retravaillés au niveau de la conception.

Chapitre 11 Cours B4: Programmation et Développement 00 8/23

17/06/2001 Chapitre 11: Conception Détaillée 5/17

Exemple de classes de conception détaillée: Le design pattern « State »

EtatConcret2

evenement1(UneMachine : Machine)evenementn(UneMachine : Machine)

EtatConcret1

evenement1(UneMachine : Machine)evenement2(UneMachine : Machine)

Machine

evenement1()evenement2()evenementn()

EtatAbstrait

evenement1(UneMachine : Machine)evenement2(UneMachine : Machine)evenementn(UneMachine : Machine)

+etat

etatn() { etat.etatn(this);}

Le design pattern « état » décrit par E. Gamma a pour objet de simplifier l’écriture des classes qui ont des états internes nombreux et compliqués. Si le comportement d’une ou plusieurs méthode de la classe dépendent d’états interne de la classe, il peut être judicieux de séparer les responsabilités dans plusieurs classes en utilisant le design pattern « State » Le dp state est une solution au problème de « comment faire dépendre le comportement de l’état » Il définit une classe « Machine » qui permet de présenter une interface unique au monde extérieur, et une classe « EtatAbstraite » Il représente les différents états de la machine d’états comme des classes dérivées de la classe de base « EtatAbstrait ». Il définit les comportements spécifiques dans la classe dérivée appropriée Il maintient un pointeur vers l’état courant dans la classe « Machine » Il modifie l’état de la machine en modifiant la valeur du pointeur sur l’état courant.

Chapitre 11 Cours B4: Programmation et Développement 00 9/23

17/06/2001 Chapitre 11: Conception Détaillée 6/17

Le pattern State appliqué au suivi de mission

en route

event Incident/ CreerIncidentTransport(type)

en etape

event incident/ creerIncidentEtape

départ

départ étape / recalculerTemps

retour

arrivéeEtape / recalculerEtapes

SuiviMission/ heureDepart : Date {readOnly}/ heureArrivee : Date {readOnly}

depart()retour()arriveeEtape()departEtape()incident(). ..

SuiviMissionEtat

arriveeEtape()departEtape()incident()retour()

1

-etat

1

délègue

SuiviMissionEnRoute

arriveeEtape()departEtape()incident()retour()

SuiviMissionEnEtape

arriveeEtape()departEtape()incident()

{ignore}{ignore}{abstract}{ignore}

Chapitre 11 Cours B4: Programmation et Développement 00 10/23

17/06/2001 Chapitre 11: Conception Détaillée 7/17

Implémentation en C++class SuiviMission {

friend SuiviMissionEtat;

protected:

SuiviMissionEtat* _etat;

public:

SuiviMission() {

_etat = new suiviMissionEtat();};

void depart() {

_etat->depart(this);};

void retour() {

_etat->retour(); }

void incident() {

_etat->incident(this);};

void departEtape() {

_etat->departEtape(this);};

void ariveeEtape() {

_etat->arriveeEtape(this);};

};

class SuiviMissionEtat {

public:

SuiviMissionEtat() {};

void depart(SuiviMission UneMission) {

UneMission->_etat = newUneMissionEnRoute();

delete this;

};

virtual void arriveeEtape(SuiviMission UneMission) {};

virtual void departEtape(SuiviMission UneMission) {};

virtual void incident(SuiviMission UneMission) {};

virtual void retour(SuiviMission UneMission) {};

};

class SuiviMissionEnRoute() {

public:

SuiviMissionEnRoute() {};

void incident(SuiviMission UneMission) {

// creerIncidentTransport(); };

void retour(SuiviMission UneMission) {

UneMission->_etat = new SuiviMissionEtat();

delete this; };

void arriveeEtape(SuiviMission UneMission) {

// recalculerEtapes

UneMission->_etat =

new SuiviMissionEnEtape();

delete this; };

};

class SuiviMissionEnEtape() {

public:

SuiviMissionEnEtape() {};

void incident(SuiviMission UneMission) {

// creerIncidentEtape };

void DepartEtape(SuiviMission UneMission) {

//RecalculerTemps

UneMission->_etat = newSuiviMissionEnRoute();

delete this; };

};

Chapitre 11 Cours B4: Programmation et Développement 00 11/23

17/06/2001 Chapitre 11: Conception Détaillée 8/17

Conception des associations (simples)

L’association se transforme en tableau ou en attribut en f(cardinalité)La conception des associations est facilité par l’expression de la navigabilitéL’utilisation de « design tip » documentés permet d’alléger la description de la conception des associations

MissionTraction

Commande

Agence

*

+destination 1*

transporte

MissionTraction

Destination : AgencelstCommande : Vector<Commande>

ajouterDestination(a:Agence):booleenDestination() : AgenceajouterCommande(c:Commande):booleenretirerCommande(c:Commande):booleenlisterCommande():Vector<Commande>

Détail des attribut et des opérations mis en œuvre par défautEt regroupés sous design tip = default

L'association est un concept inconnu de la plupart des langages orientés objet. Elle se transforme en attribut ou en tableau d'attributs suivant sa multiplicité. Une agrégation, outre la précision sémantique qu'elle apporte en analyse, n'est pratiquement jamais prise en compte en conception. Remarquons également que l'utilisation du tableau générique Vector de Java ne permet pas d'exprimer le type d'éléments stockés. L'usage d'une notation empruntée au template de C++ permet de conserver cette information sur le diagramme. La conception des associations est facilitée par l'expression de leur navigabilité. Il serait cependant fastidieux de transformer tous les diagrammes de conception, d'autant que la conception d'une association s'accompagne d'un ensemble d'opérations nécessaires à sa gestion. On utilise donc une valeur étiquetée, « design tip » pour désigner les mécanismes d'association accompagnés de leurs opérations de gestion. Ce mécanisme doit donc être documenté dans le modèle. La visibilité des opérations de gestion de l'association étant identique à la visibilité du rôle, il est important d'introduire cette information en conception détaillée.

Chapitre 11 Cours B4: Programmation et Développement 00 12/23

17/06/2001 Chapitre 11: Conception Détaillée 9/17

Conception des associations (complexes)

Elle se complique si des contraintes doivent être respectéesLes contraintes de gestion (>0, frozen…) se traduisent par la modification de l’interface de la classeLes contraintes structurelles (XOR, classe d’association, association bidirectionnelle) introduisent des post-conditions au opérations de gestion et l’ajout de règles de gestion

La conception d'une association se complique lorsqu'elle comporte des contraintes à respecter. On peut considérer deux types de contraintes différentes et adapter le style de conception en conséquence. Les contraintes de gestion sont exprimées par une multiplicité minimale supérieure à 0 (obligatoire), une composition, un qualifieur ou les propriétés d'UML {ordered}, {addOnly} et {frozen}. Ces contraintes ont des répercussions sur l'interface et les méthodes de gestion d'une seule association. Par exemple, l'opération de retrait peut disparaître du fait d'un addOnly ou d'un frozen, le constructeur doit comporter des paramètres supplémentaires pour initialiser les liens const ou obligatoires. Une composition se traduit par la destruction des composantes lors de la destruction du composite; (cette contrainte a peu d'influence appliquée à Java grâce au garbage collector). Enfin, les qualifieurs transforment un Vector en Hashtable dont la clé est le type du qualifïeur. D'autres contraintes structurelles portent sur plusieurs associations : il peut s'agir des contraintes utilisateur, des contraintes prédéfinies {XOR}, {subset} et {AND}, des associations bidirectionnelles ou d'une classe d'association. Ces contraintes induisent des postconditions aux opérations de gestion de l'association. Les associations bidirectionnelles sont conçues exactement comme deux associations réciproques, dont les attributs de part et d'autre sont synchronisés par règle de gestion. Une association avec classe se transforme en deux associations centrées sur la classe d'association. Cette dernière étant le

Chapitre 11 Cours B4: Programmation et Développement 00 13/23

plus souvent responsable de synchroniser les deux liens, comporte les opérations de gestion de l'association. Concevoir les associations consiste enfin à transformer les associations n-aires, tolérées par les analystes, en formes binaires gérées par le concepteur, ou bien à ajouter une nouvelle classe qui pilote la relation complexe. Dans un second temps, il est possible d'optimiser les méthodes de gestion. Le cas le plus fréquent concerne la consultation d'une liste d'objets en mode client/serveur. D'une part, le transfert d'un groupe d'objets est coûteux pour le réseau, alors qu'il suffit d'afficher un seul libellé caractéristique pour chaque objet. D'autre part, au delà de 10 à 20 références, un utilisateur reformule la plupart du temps son critère de sélection. Pour éviter des temps d'attente, on peut procéder à la gestion d'une liste de libellés caractéristiques, par un curseur ramenant 10 à 20 références à la fois.

Chapitre 11 Cours B4: Programmation et Développement 00 14/23

17/06/2001 Chapitre 11: Conception Détaillée 10/17

Design pattern Itérateur

Le design pattern Itérateur [Gamma 95] est une façon de concevoir l'accès séquentiel à un ensemble d'objets, sans avoir à exposer la structure interne de l'ensemble. Par ailleurs, l'itérateur offre une interface de parcours standard qui uniformise et facilite la manipulation des différents types de liste d'un même projet. Il offre enfin la possibilité de parcourir simultanément et indépendamment le même ensemble d'objets par des tâches parallèles. L'objectif de l'itérateur est de déléguer les opérations de parcours d'une association. Par ailleurs, il a pour rôle de gérer l'état d'un élément courant, auquel on peut accéder séquentiellement au précédent ou au suivant. L'itérateur est donc particulièrement approprié aux associations ordonnées (propriété (ordered)). la classe responsable de gérer l'association sert naturellement de fabrique d'itérateur.

Chapitre 11 Cours B4: Programmation et Développement 00 15/23

17/06/2001 Chapitre 11: Conception Détaillée 11/17

Exemple d’itérateurclass Stack {int items[10];int sp;public:friend class StackIter;Stack() { sp = -1; }void push( int in ) { items[++sp] = in; }int pop() { return items[sp--]; }bool isEmpty() { return (sp == -1); }

// 2. Add a createIterator() memberStackIter* createIterator() const;

};

class StackIter { // 1. Design an "iterator" class const Stack* stk;int index;

public:StackIter( const Stack* s ) { stk = s; }void first() { index = 0; }void next() { index++; }bool isDone() { return index == stk->sp+1; }int currentItem() { return stk->items[index]; }

};

StackIter* Stack::createIterator() const { return new StackIter( this ); }

bool operator==( const Stack& l, const Stack& r ) {// 3. Clients ask the container object to create an iterator object

StackIter* itl = l.createIterator(); StackIter* itr = r.createIterator();

// 4. Clients use the first(), isDone(), next(), and currentItem() protocol for (itl->first(), itr->first();

!itl->isDone() || !itr->isDone();itl->next(), itr->next())

if (itl->currentItem() != itr->currentItem())break;

bool ans = itl->isDone() && itr->isDone();delete itl;delete itr;return ans;

}

Impléméntation d’une classe stack et de son itérateur On peut rajouter l’opération == sur les piles qui n’étaient pas prévues grâce à l’itérateur.

Chapitre 11 Cours B4: Programmation et Développement 00 16/23

17/06/2001 Chapitre 11: Conception Détaillée 12/17

Conception des attributsDéfinition du type des attributs identifiés en analyseIdentification des structures et des énumérationsSpécification de la visibilité et du mode d’accèsSpécification des méthodes de mise à jour des attributs dérivés

La conception des attributs consiste principalement à définir le type des attributs identifiés en analyse. Bien que la plupart des attributs se satisfassent des types de base de lava, certains attributs d'analyse correspondent à une structure de données qu'il est nécessaire de spécifier. Dans ce cas, nous introduisons le stéréotype struct pour distinguer une simple structure de données d'une classe. Cette dernière s'apparente à un type de base du langage ;tous ses attributs sont publics, de sorte qu'elle nécessite rarement d'opérations associées. D'autres attributs induisent des énumérations pour lesquelles nous introduisons également le stéréotype enum. En Java, une énumération correspond à une classe composée d'attributs public static final. Concevoir les attributs, c'est également spécifier leur visibilité et leur mode d'accès. Par défaut, un attribut est privé et ce principe reste invariable dans notre conception. La prise en compte des propriétés UML {changeable), {readOnly} ou {frozen} est donc implicitement gérée par des opérations d'accès. Pour assurer respectivement la modification et la lecture de la valeur de l'attribut, les attributs {changeable) requièrent deux opérations set<nom attribut> et get<nom attribut>. La propriété {frozen} implique l'initialisation de l'attribut dans le constructeur de la classe. Cela se traduit le plus souvent par un paramètre d'initialisation supplémentaire. Nous avons ajouté la propriété {readOnly} pour indiquer que l'attribut n'est disponible qu'en lecture grâce à l'opération gel.

Chapitre 11 Cours B4: Programmation et Développement 00 17/23

Enfin, concevoir les attributs, c'est spécifier les méthodes qui servent à la mise à jour des attributs dérivés. Il existe à cet effet plusieurs techniques, la plus simple consistant à invoquer une opération de mise à jour lors de l'accès à l'attribut. Certaines méthodes de calcul peuvent cependant être coûteuses ou fréquentes, aussi faut-il gérer un attribut d'état pour recalculer l'attribut dérivé uniquement si l'opération se justifie. La gestion des attributs dérivés dans une application parallèle nécessite parfois la conception de synchronisations complexes.

Chapitre 11 Cours B4: Programmation et Développement 00 18/23

17/06/2001 Chapitre 11: Conception Détaillée 13/17

Conception des opérationsDonner une image précise du contenu des méthodesUtilisation du diagramme d’activités Utilisation du diagramme d’interactionsUtilisation de la réification pour transformer des comportements dynamiques en classes et alléger les responsabilités d’une classeLa description des méthodes permet d’identifier de nouvelles méthodes et de nouvelles classes

La conception des opérations constitue la dernière étape du micro-processus de conception. Le plus gros du travail est certainement fourni lors de cette étape. Il s'agit en effet de donner une image assez précise du contenu des méthodes du projet. Pour concevoir ou documenter une méthode, UML met à notre disposition toute la palette des diagrammes du modèle dynamique. Un diagramme d'activités permet de décrire une méthode pour laquelle peu de classes différentes interviennent. Ce diagramme se révèle efficace lorsque la méthode met en jeu un algorithme avec des étapes et de nombreuses alternatives. Un diagramme d'interactions expose au contraire une méthode faisant intervenir plusieurs classes, mais avec peu d'alternatives. Certaines méthodes traversent des états de calcul stables et nécessitent un contexte de variables pour mémoriser leur avancement. Elles se transforment aisément en classe lors de la conception. Cette technique, depuis longtemps connue des concepteurs objet, s'appelle la réification. RÉIFICATION

Chapitre 11 Cours B4: Programmation et Développement 00 19/23

Réifier consiste à traiter en objet ce qui n'est pas usuellement considéré comme un objet (Rumbaugh) Cette technique est particulièrement utile pour transformer des comportements dynamiques en classes que l'on peut alors stocker et associer avec d'autres éléments du modèle. Elle peut accompagner une délégation de responsabilités pour une classe qui aurait tendance à concentrer trop de rôles (syndrome de la classe obèse) et constitue un idiome de conception qui apporte souplesse et évolution à la solution. En conséquence, un diagramme d'états peut être utilisé pour décrire les états que traversent une méthode réifiée. Ce diagramme montrant les successions possibles d'actions et d'activités s'apparente à un diagramme d'activités. En pratique, la description des méthodes permet d'identifier de nouvelles responsabilités à assigner aux différentes classes du système. C'est ainsi qu'apparaissent tantôt de nouvelles opérations sur les classes existantes, tantôt de nouvelles classes techniques provenant de l'application de design patterns. Les nouveaux éléments de modélisation alimentent alors une nouvelle itération sur le micro-processus de construction jusqu'à l'obtention d'un modèle facile à coder. Ce processus suit le principe d'une approche top-down (du plus abstrait vers le plus détaillé), mise en place à l'aide des techniques traditionnelles de décomposition fonctionnelle.

Chapitre 11 Cours B4: Programmation et Développement 00 20/23

17/06/2001 Chapitre 11: Conception Détaillée 14/17

Exemple de conception d’opérations

Client : Mission : Suiv iMission commande.enCours : EnCours DeCmd

: PassageD...

signalerDepart(Date)<<create>>

depart( )

les Commandes := lstCommandes()*[i=1 ,nbC ommande] departAgence( Date)

setDepartAgence(Date)

recalculerDatesPassage

recalculerDateLiv raison

Package SIVEx.metier.mission;

Public class SuiviMission {_mission = mission;…

}

Public void depart() {int i=0;Vector lesCmd = _mission.lstCommandes();Commande cmd;EnCoursDeCommande ecmd;for (i = 0; i < lesCmd.size(); i++) {cmd = (Commande)lesCmd.elementAt(i);ecmd.departAgence(

_mission.getDateDepart());}

}…}

Package SIVEx.metier.commande;…

Public class EnCoursCommande {_depart = date;recalculerDatesPAssages();recalculerDatesLivraison();

}}

Opération Mission::signalerDepart Le signal de départ d’une mission entraîne une chaîne de messages dans le système qui permet la mise en jour des informations d’encours de commande. Le diagramme de séquence est le plus approprié pour documenter ce type de méthode mettant en jeu plusieurs classes différentes.

Chapitre 11 Cours B4: Programmation et Développement 00 21/23

17/06/2001 Chapitre 11: Conception Détaillée 15/17

Exemple de réification

{design tip = default}

OrdonnateurDEtapestabResultat : Vector<Etape>tabInitial : Vector<Etape>tabUrgence : Vector<boolean>

executer(laMission : MissionDeTournee)initialiser()positionnerDepartRecherche()rechercherEtapeSuivante() : intrechercherEtapeSuivanteOptimale() : intordonnerResultat()ordonnerMission()

MissionDeTournee

exécute

0..1-laMission0..1

{changeable}

EtapenoEtapen 0..1n

noEtape+etape

0..1traite

{ordered}

Commande

n

1

n

+commande1

traite

{frozen}

initialiser

PositionnerDepartRecherche

Méthode OrdonnateurDEtapes::executer

rechercherEtapeSuivante rechercherEtapeSuivanteOptimale

OrdonnerResultat

else[ etapes restantes ]

else [ urgences à traiter ]

public void executer() {int err = 1;_initialiser();while _tabResultat.size() < _tabInitial.size()&& err > 0) {

_positionnerDepartRecherche();if (_tabUrgence.size() > 0)err=_rechercherEtapeSuivanteOptimale();

elseerr=_rechercherEtapeSuivante();

_ordonnerResultat();}

}

Class OrdonnateurDEtapes {Public OrdonnateurDEtapes(Mission laMission) {

int i;_laMission = laMission;_tabInitial = laMission.lstEtapes();_tabUrgence = new Boolean[_tabInitial.size()]for (i = 0; i < _tabInitial.size(); i++) {Etape etape = (Etape) _tabInitial.elementAt(i);_tabUrgence[i]=etape.commande.estUrgente();

}

Chapitre 11 Cours B4: Programmation et Développement 00 22/23

17/06/2001 Chapitre 11: Conception Détaillée 16/17

Design pattern « Stratégie »

StrategieConcreteA StrategieConcreteB StrategieConcreteC

Contexteparam

Contexte(s : Strategie)excuterStrategie()

Strategie

executer(contexte : Contexte)

<<Interface>>

n 1n 1

Client choix : StrategieConcr...

ctx : Contexte

<<create>>Contexte(StrategieConcrete)

executer( ctx)

excuterStrategie( )

param := getParam()setResult()

r := getResult()

setParam(param)

Le design pattern stratégie consiste à encapsuler une famille d’algorithmes qui s’exécutent dans un contexte identique. La stratégie utilise la réification pour transformer les algorithmes en classes puis l’héritage d’interface pour organiser ces classes en arbre de spécialisation. Le contexte d’une stratégie sert de réceptacle à ses paramètres d’entrée/sortie et de déclencheur pour son comportement On a recours à une stratégie lorsqu’on a besoin de différentes variantes de comportement s’exécutant en fonction de conditions extérieures à la classes. On utilise aussi la stratégie pour développer des variantes dépendantes d’un paramétrage ou d’un choix opérateur.

Chapitre 11 Cours B4: Programmation et Développement 00 23/23

17/06/2001 Chapitre 11: Conception Détaillée 17/17

Exemple de stratégieContexteReceptionEvt

reception : ReceptionEvtsuivi : SuiviMission {changeable}evt : EvenementMission {changeable}

ContexteReceptionEvt(rcpt : ReceptionEvt)executerReception()

ReceptionEvt

executer(ctx : ContexteRecept ionEvt)

<<Interface>>

ReceptionIncidentTrajet ReceptionIncidentEtape

ReceptionClientAbsent

ReceptionRefus

ReceptionAdresseIncorrecte ReceptionPaiementNonEffectue

ReceptionAnomalieEnlevement

ReceptionAnomalieLivraison

ReceptionEvtSimple

ReceptionRetardDepart

ReceptionRetard

ReceptionPanneNonBloquante

ReceptionEtapeNonRespectee

Client sm : SuiviMission

: FabriqueRec...

ctx : ContexteRe...

rcpt : ReceptionRefus

recevoirEvenement(EvenementMission)

rcpt := reception( EvenementMission)

ContexteReceptionEvt(ReceptionEvt)

setSuiviMission( sm)

setEvenementMission( EvenementMission)

executerReception( )

<<create>>

executer( ctx)

Le traitement d’un événement mission est effectué par le suivi d’une mission en cours. La réception d’un événement s’exécute toujours dans le même contexte, mais donne lieu à des comportements différents suivant le type d’événement. En analyse, on a distingué les évènements simples, les incidents d’étape et les incidents de trajet. Suivant leur nature ces évènements engendre des traitements différents (réponse du répartiteur, recalcul des trajets…) En raison de ces différents traitements, une stratégie permet de maintenir la séparation entre les algorithmes.