Principes et conseils : Implémenter les classes
Pour implémenter les opérations, effectuez les étapes suivantes :
- Sélectionner un algorithme.
- Choisir des structures de données appropriées aux algorithmes.
- Définir de nouvelles classes et de nouvelles opérations si nécessaire.
- Coder l'opération.
Sélectionner un algorithme
Beaucoup d'opérations sont assez simples pour être implémentées à partir de l'opération et de sa spécification.
Des algorithmes complexes sont requis pour deux raisons principales : pour implémenter les opérations complexes pour lesquelles une spécification est fournie, et pour optimiser les opérations pour lesquelles un algorithme simple mais inefficace sert de définition.
Sélectionner les structures de données adaptées aux algorithmes
Le choix des algorithmes implique le choix de la structure de données sur laquelle ils sont utilisés. De nombreuses structures de données d'implémentation sont des classes de conteneurs (séries, listes, files d'attente, piles, ensembles et variations de ces éléments). La plupart des langages orientés objet et des environnements de programmation fournissent des bibliothèques de classes contenant ces types de composants réutilisables.
Définir de nouvelles classes et opérations selon les besoins
On peut identifier de nouvelles classes pour stocker les résultats intermédiaires, par exemple. De nouvelles opérations de bas niveau peuvent être ajoutées à la classe pour décomposer une opération complexe. Ces opérations sont souvent privées et appartiennent à la classe, c'est-à-dire qu'elles ne sont pas visibles hors de la classe elle-même.
Coder l'opération
Ecrire le code de l'opération en commençant par sa déclaration d'interface. Suivez les recommandations de programmation applicables.
L'état d'un objet peut être implémenté en faisant référence aux valeurs de ses attributs, sans aucune représentation spécifique. Les transitions d'état d'un tel objet sont implicites dans les valeurs des attributs, et les différents comportements sont programmés via des instructions conditionnelles. Cette solution n'est pas satisfaisante pour les comportements complexes car elle aboutit généralement à des structures complexes difficiles à modifier au fur et à mesure de l'ajout d'états supplémentaires ou du changement des comportements.
Si le comportement de l'élément de conception (ou de ses éléments constitutifs) est dépendant de l'état, il existera au moins un diagramme d'état-transition décrivant le comportement des éléments du modèle dans l'élément de conception. Au cours de l'implémentation, ces diagrammes d'état-transition constituent des éléments d'entrée importants.
Les automates à états illustrés dans les diagrammes rendent explicites les états des objets ; les transitions et le comportement requis sont également clairement définis. Pour implémenter un automate à états, vous avez le choix entre les méthodes suivantes :
- Pour les automates à états simples, définissez un attribut qui énumère les états possibles et utilisez-le pour sélectionner le comportement pour les messages entrants. Par exemple, dans une déclaration de commutateur en Java ou en C++. Cette solution n'est pas très adaptée aux automates à états complexes et peut conduire à de mauvaises performances d'exécution. Pour obtenir un exemple de cette méthode, voir [DOUG98], Chapitre 4,
4.4.3
- pour les automates à états plus complexes, vous pouvez utiliser le pattern d'état. Pour obtenir la description du pattern d'état, voir [GAM94]. [DOUG98],
Chapitre 6, 6.2.3, State Pattern, décrit également cette approche
- une approche basée sur les tables fonctionne bien pour les automates à états très complexes, pour lesquelles la simplicité de modification constitue un critère. Pour chaque état, chaque entrée d'une table correspond aux entrées des états suivants appropriés et aux actions de transition associées. Pour obtenir un exemple de cette méthode, voir [DOUG98], Chapitre 6, 6.2.3, State Table Pattern.
Les automates à états contenant des sous-états concurrents peuvent être implémentées en déléguant la gestion des états à des objets actifs (un pour chaque sous-état), car ces sous-états représentent des calculs indépendants (qui peuvent toutefois être en interaction).
Chaque sous-état peut être géré à l'aide de l'une des techniques décrites ci-dessus.
Si une classe ou les parties d'une classe peuvent être implémentées par la ré-utilisation d'une classe existante, utilisez la délégation plutôt que l'héritage.
Déléguer signifie que la classe est implémentée avec l'aide d'autres classes.
La classe référence un objet de l'autre classe à l'aide d'une variable. Lorsqu'une opération est appelée, elle appelle à son tour une opération dans l'objet référencé (de la classe réutilisée) pour procéder à l'exécution. Par conséquent, vous pouvez considérer qu'elle délègue une part de responsabilité à l'autre classe.
Une association unidirectionnelle est implémentée comme un pointeur (attribut contenant une référence à un objet). Si la multiplicité est égale à un, elle est implémentée comme un pointeur simple. Si la multiplicité prévoit plusieurs occurrences, il s'agira alors d'un ensemble de pointeurs. Si l'option plusieurs est retenue, vous pouvez utiliser une liste plutôt qu'un ensemble.
Une association bidirectionnelle est implémentée en tant qu'attribut à deux sens, à l'aide des techniques applicables aux associations unidirectionnelles.
Une association qualifiée est implémentée comme une table de recherche (par exemple, une classe de dictionnaire Smalltalk) dans l'objet qualifiant. Les valeurs de sélection de la table de recherche sont les qualificatifs et les valeurs cible sont les objets de l'autre classe.
Si les valeurs des qualificatifs doivent faire l'objet d'un accès selon un certain ordre, les qualificatifs peuvent être organisés sous forme d'ensemble trié ou d'arborescence. Dans ce cas, le temps d'accès sera proportionnel à log N (N représentant le nombre de valeurs de qualificatifs).
Si les qualificatifs sont issus d'un ensemble compact fini, leurs valeurs peuvent être mappées au sein d'une plage de nombres entiers et l'association peut être implémentée efficacement. Cette approche est plus attrayante, surtout si l'association est bien remplie (par opposition à une association avec peu d'éléments) et elle est idéale pour les ensembles finis et complets.
La plupart des langages orientés objet et des environnements de programmation fournissent des bibliothèques de classes contenant des composants réutilisables permettant d'implémenter différents types d'associations.
Pour implémenter les attributs, appliquez l'une des trois méthodes suivantes : utilisez des types primitifs intégrés, une classe existante, ou encore une nouvelle classe. La définition d'une nouvelle classe est souvent plus souple, mais elle induit un aspect indirect inutile. Par exemple, le numéro de sécurité sociale d'une personne peut être soit implémenté en tant qu'attribut de type Chaîne, soit sous forme d'une nouvelle classe.

Autres implémentations d'attribut.
Il peut également arriver que des groupes d'attributs soient combinés pour constituer de nouvelles classes, comme l'illustre l'exemple suivant. Les deux implémentations sont correctes.

Les attributs Line sont implémentés sous forme d'associations à une classe Point.
|