Les ancêtres d'un bloc doivent être implémentés en premier. Article doit être implémenté avant Canette. A travers la conception nous avons spécifier implicitement les protocoles de chaque bloc. En prenant l'ensemble des Diagrammes d'interaction nous pouvons extraire tous les occurrences d'un bloc et donc connaître toutes les opérations qui sont définies pour ce bloc. Nous obtenons ainsi une image complète des interfaces de notre bloc. Ces interfaces sont apparues pendant la conception des services et plusieurs personnes ont contribué à leur définition, elle ne sont pas en générale définie dans le même document. Mais ces interface existe de façon explicite (ici un outil CASE peut être très utile) et peuvent être extraite mécaniquement.
Regardons ce que cela donne sur notre exemple. Nous parcourons les diagrammes d'interaction et l'on extrait tous les opération définie sur le bloc. Du Diagramme 1.10 nous pouvons extraire les interfaces suivantes pour article
existeet BaseDeReçu
incr
nom
nombre
ajouter(article)
imprime(File)
free
Ce qui nous permet de fabriquer l'interface des blocs. Regardons le bloc BaseDeReçu. Nous pouvons fabriquer une première version de notre classe : Class BaseDeRecu opérations
Ce qui s'exprime en suite dans le langage de programmation. Dans l'exemple suivant en C++ nous avons utiliser la conception en C++ décrite Figure 1.16 pour BaseDeRecu. Nous avons deux classe composant visible uniquement grâce à l'include "#include "linkedlist.h". Nous avons ici une classe privée au bloc qui n'est utilisé qu'ici ArticleInséré.
// File BaseDeRecu.h
#include "linkedlist.h"
#include "stream.h"
// classe prive (encapsulee dans le bloc)
class ArticleInsere : public Link {
private :
Article * articleDepose;
int nombretotal;
public:
ArticleInsere(Article *a);
Article *getarticle();
void incr();
int total();
~ArticleInsere();
};
// classe publique
class BaseDeRecu {
private:
LinkedList *listeArticle;
float somme;
public:
BaseDeRecu(); // creation en C++
void ajouter(Article *);
void imprime(File *);
~BaseDeRecu(); // destruction en C++
}.
Même chose en Objective C.
// fichier ArticleInsere.h
@Class(Article)
@interface ArticleInsere : Objet
{
Article *
int nombreTotal;
}
+ alloc; // creation en ObjectiveC
+ init:Article *a;
- incr;
- total;
- (Article *) article;
-free; // destruction en ObjectiveC
@end
// fichier BaseDeRecu.h
#import "List.h"
#import "ArticleInsere.h"
@interface BaseDeRecu : List // herite de la
{
private:
Article * articleDepose;
int nombretotal;
}
- (void) ajouter:Article *a;
- (void) imprime:File *;
@end
En parcourrant tous les Diagrammes d'interaction nous obtenons une spécification d'interface complète. Nous avons aussi une description partiel des opérations grâce à la partie droite des diagrammes.
A ce moment il devient possible de geler l'interface des blocs. En gelant l'interface de certain bloc il devient possible de commencer la conception interne des blocs en parallèle. En plus des prèrequis définis dans la conception des services. IL existe d'autre pré-requis sur les blocs. Ces besoins peuvent être identifiés à partir du modèle d'analyse ou nous trouvons les attributs et les type des attributs que notre bloc doit contenir. D'autres besoins peuvent venir des spécifications des pré-requis, par exemple les besoins temps réel, ou des spécifications sur la consommation mémoire. En général un bloc correspond à une seule classe et ces instances. Il est alors facile de relier l'interface d'un objet dans la conception avec l'interface d'un objet dans l'implémentation. Dans d'autre cas plusieurs classes seront nécessaires pour implémenter le bloc. Ceci est en général causé par la nécessité de s'adapter à différents environnements d'implémentation. Mais certaines classes comporte l'implémentation d'un attribut, l'utilisation de composants et l'extraction de fonctionnalitées communes dans une classe abstraite. Pour gérer l'interface d'un bloc nous pouvons utiliser les concepts utilisés par le langage de programmation (comme dans l'exemple précédent). Les blocs restent une abstraction et un mécanisme d'encapsulation. Ainsi nous pouvons exprimer l'interface d'un bloc plus explicitement et nous pouvons encapsuler sont implémentation effective. Nous réalisons cette encapsulation en utilisant des modules privés ou publiques suivant si il appartienent à l'interface d'un bloc ou si il sont internes à un bloc. Dans l'exemple seul BaseDeRecu est publique et cache les détails de l'implémentation. conception.impl1.bisLes parties privées et publiques d'un bloc. Cacher les détails d'implémentation internes est un moyen de réduire la complexité du source. Mais avec cette technique nous devons déterminer très tôt quelles classe sont publiques et quelles classes sont priver et donc prendre des décisions sur l'implémentation des blocs. Mais ce qui est effectivement nécessaire est de définir une interface qui satisfasse les besoins et qui défini correctement le rôle de l'objet. Pour les autres implémenteurs de blocs nous devons définir les types que nous offrons et les opérations sur ces types. Un ou plusieurs de ces types deviendrons une classe dans le bloc. Nous pouvons ainsi définir ces types comme des responsabilités et des contrats du bloc (Wirfs-Brock et al. (1990)). Illustré Figure 1.17
blocdesignLe bloc et le type exporté.
Next: Le comportement des objets Up: La conception par Blocs Previous: L'interface d'un bloc
Pour vos remarques ou sugestions copyright D.revuz 1995