Utilisation de patterns et de mécanismes de conception
Utilisez les patterns et les mécanismes de conception correspondant à la classe ou à la fonction en train d'être
conceptualisée et étant en accord avec les instructions relatives à la conception du projet.
L'ajout d'un pattern et/ou d'un mécanisme a pour effet de réaliser concrètement plusieurs des étapes ultérieures de
cette tâche (ajout de nouvelles classes, d'opérations, d'attributs et de relations) mais en conformité avec les règles
définies par le pattern ou le mécanisme.
Notez que les patterns et les mécanismes sont généralement ajoutés à mesure que la conception évolue et pas seulement
lors de la première étape de cette tâche. Ils sont aussi fréquemment appliqués par un ensemble de classes plutôt que
par une classe unique.
|
Création des classes de conception initiales
Créez une ou plusieurs classes de conception initiales pour la classe d'analyse donnée comme entrée à cette tâche et
attribuez des dépendances de trace. Les classes de conception créées à cette étape seront détaillées, ajustées,
partagées ou fusionnées lors des étapes suivantes, lorsqu'on leur attribuera des propriétés de conception comme des
opérations, des méthodes et une machine d'état qui décrit comment la classe d'analyse est conceptualisée.
Selon le type de classe d'analyse (frontière, entité ou de contrôle) en cours de conception, il existe plusieurs
stratégies que vous pouvez utiliser pour créer des classes de conception initiales.
Les classes frontière représentent les interfaces pour les utilisateurs ou les autres systèmes.
En général, les classes frontière qui représentent des interfaces pour d'autres systèmes sont modélisées sous forme de
sous-système car elles ont souvent un comportement interne complexe. Si le comportement de l'interface est simple (ne
jouant, par exemple, que le rôle de passe-système vers une interface de programme d'application du système externe),
vous pouvez décider de représenter l'interface à l'aide d'une ou plusieurs classes de conception. Si vous choisissez
cette option, utilisez une seule classe de conception par protocole, interface ou interface de programme d'application
et souvenez-vous des exigences particulières concernant les standards que vous avez utilisés dans les exigences
particulières de la classe.
Les classes frontière qui représentent des interfaces pour les utilisateurs suivent généralement la règle d'une classe
frontière pour chaque fenêtre ou pour chaque formulaire dans l'interface utilisateur. Les responsabilités d'une classe
frontière peuvent donc être très grandes et avoir besoin d'être détaillées lors de cette étape. Les modèles ou les
prototypes additionnels de l'interface utilisateur peuvent être une autre source d'entrée à prendre en compte lors de
cette étape.
La conception des classes frontière dépend des outils de développement de l'interface utilisateur disponibles pour le
projet. En utilisant la technologie actuelle, il arrive souvent que l'interface utilisateur soit construite
visuellement directement dans l'outil de développement. Cela crée automatiquement des classes d'interface utilisateur
qui ont besoin d'être associées à la conception des classes de contrôle et des classes entité. Si l'environnement de
développement de l'interface utilisateur crée automatiquement les classes de support dont il a besoin pour implémenter
l'interface utilisateur, ce n'est pas la peine de les prendre en compte lors de la conception. Vous devez
conceptualiser ce que l'environnement de développement ne crée pas pour vous.
Lors de l'analyse, les classes entité représentent des unités d'information manipulées. Elles sont souvent passives et
persistantes et peuvent être identifiées et associées au mécanisme d'analyse pour la persistance. Vous trouverez les
détails concernant la conception de mécanismes persistants basés sur des bases de données dans Tâche : conception de base de données. Des considérations portant sur
les performances pourraient entraîner la restructuration des classes persistantes, causant des changements dans le
modèle de conception qui sont abordés à la fois dans Rôle :
concepteur de base de données et dans Rôle :
concepteur.
On reviendra plus en détails sur les problèmes de conception des classes persistantes dans une partie intitulée Identification des classes persistantes.
Un objet de contrôle est responsable de la gestion du flux d'un cas d'utilisation et coordonne donc la plupart de ses
actions ; les objets de contrôle encapsulent une logique qui n'est vraiment liée, ni aux problèmes d'interface
utilisateur (objets frontière), ni aux problèmes de gestion des données (objets entité). Cette logique est parfois
appelée logique applicative ou logique métier.
Prenez en compte les problèmes suivants lorsque les classes de contrôle entrent en jeu :
-
Complexité - Vous pouvez gérer les comportements de commande ou de coordination simples en utilisant une
classe entité ou une classe frontière. Toutefois, à mesure que la complexité de l'application devient plus
importante, cette approche présente de nombreux désavantages. En voici quelques exemples :
-
le comportement de coordination du cas d'utilisation est inclus dans l'interface utilisateur, rendant le
système plus difficile à changer
-
la même interface utilisateur ne peut pas être utilisée par différentes réalisations de cas d'utilisation sans
difficulté
-
l'interface utilisateur est surchargée par des fonctionnalités supplémentaires, entraînant une dégradation de
ses performances
-
les objets entité peuvent être surchargés par le comportement spécifique des cas d'utilisation, diminuant leur
généralité.
Pour éviter ces problèmes, des classes de contrôle sont introduites pour fournir les comportements associés aux
flux d'événements coordonnant.
-
Probabilité de changement - Si la probabilité de changer les flux d'événements est faible ou si le coût est
minime, les dépenses supplémentaires liées à des classes de contrôle supplémentaires, ainsi que leur complexité, ne
sont pas forcément justifiées.
-
Distribution et performances - Le besoin d'exécuter des parties de l'application sur des noeuds différents
ou dans des espaces de processus différents, entraîne le besoin de spécialiser les éléments du modèle de
conception. Cette spécialisation est souvent accomplie en ajoutant des objets de contrôle et en distribuant les
comportements des classes frontière et des classes entité aux classes de contrôle. En faisant cela, les classes
frontière ne fournissent plus, petit à petit, que des services interface utilisateur, les classes entité uniquement
des services de données et les classes de contrôle le reste.
-
Gestion de transaction - Gérer des transactions est une activité de coordination classique. Sans
infrastructure prenant en charge la gestion de la transaction, une ou plusieurs classes gestionnaires de
transaction devront interagir pour assurer le maintien de l'intégrité des transactions.
Dans les deux derniers cas, si la classe de contrôle représente une unité d'exécution séparée, il peut être plus
approprié d'utiliser une classe active pour modéliser l'unité d'exécution. Dans un système en temps réel, l'utilisation
de Produit : capsules est l'approche de modélisation la plus
recommandée.
|
Identification des classes persistantes
Les classes ayant la capacité de stocker leur état de manière permanente sont appelées classes persistantes. Elles
stockent leur état pour conserver de manière permanente les informations de classe, pour sauvegarder les données en cas
d'échec du système ou pour échanger des informations. Une classe persistante peut avoir à la fois des instances
persistantes et des instances transitoires ; une classe dite "persistante" signifie juste que certaines de ses
instances peuvent avoir besoin d'être persistantes.
Introduisez des mécanismes de conception correspondant aux mécanismes de persistance trouvés pendant l'analyse. Par
exemple, selon ce dont la classe a besoin, le mécanisme d'analyse pour la persistance pourra être réalisé par un de ces
mécanismes de conception :
-
stockage en mémoire
-
carte Flash
-
fichier binaire
-
système de gestion de base de données (SGBD)
Les objets persistants ne sont pas liés qu'aux classes entité, ils peuvent aussi être utilisés pour traiter des
exigences non fonctionnelles en général. On peut penser, par exemple, aux objets persistants nécessaires à la gestion
d'informations utiles pour les commandes de processus ou au traitement d'informations d'état entre des transactions.
Identifier des classes persistantes sert à notifier au Rôle:
concepteur de base de données qu'il faut prêter une attention particulière aux caractéristiques de mémoire physique
de la classe. Cela avertit aussi le Rôle :
Architecte de logiciel que la classe a besoin d'être persistante et le Rôle : Concepteur
responsable du mécanisme de persistance que les instances de la classe doivent être persistantes.
A cause du besoin d'une stratégie de persistance coordonnée, le Rôle :
concepteur de base de données doit mapper les classes persistantes à la base de données en utilisant une structure
de persistance. Si le projet développe une structure de persistance, le développeur de structure sera aussi responsable
de la bonne compréhension des exigences de persistance des classes de conception. Pour que ces personnes aient les
informations nécessaires, il suffit, à ce stade, d'indiquer si la classe est persistante ou, plus précisément, si les
instances de la classe sont persistantes.
|
Définition de la visibilité de la classe
Pour chaque classe, définissez la visibilité de la classe dans le package où elle se trouve. Une classe publique
peut être référencée en dehors du package qui la contient. Une classe privée (ou une ayant une visibilité
implémentation) ne peut être référencée que par les classes appartenant au même package.
|
Définition des opérations
Pour identifier les opérations sur les classes de conception :
-
étudiez les responsabilités de chaque classe d'analyse correspondante en créant une opération pour chaque
responsabilité. Utilisez la description de la responsabilité comme la description initiale de l'opération.
-
étudiez les réalisations de cas d'utilisation dans la classe participe pour voir la façon dont les classes
sont utilisées par les réalisations de cas d'utilisation. Etendez les opérations, une réalisation de cas
d'utilisation à la fois, en affinant les opérations, leur description, leur type de retour et leurs paramètres. Les
exigences de chaque réalisation de cas d'utilisation relatives aux classes sont décrites textuellement dans le flux
d'événements de la réalisation du cas d'utilisation.
-
étudiez les cas d'utilisation ayant des exigences particulières afin d'être sûre de ne pas oublier des exigences
implicites de l'opération pouvant y être indiquées.
Les opérations doivent prendre en charge les messages qui apparaissent sur les diagrammes de séquence parce que les
spécifications des messages temporaires des scripts auxquels n'ont pas encore été attribué d'opération décrivent le
comportement que la classe doit exécuter. La figure 1 monter un exemple de diagramme de séquence.
Figure 1: Messages de la matrice de base pour identifier les opérations
Les réalisations de cas d'utilisation ne fournissent pas assez d'informations pour identifier toutes les opérations.
Pour trouver les opérations restantes, posez-vous les questions suivantes :
-
existe-t-il un moyen pour initialiser une nouvelle instance de la classe, comme par exemple la connecter aux
instances d'autres classes auxquelles elle est associée ?
-
est-il nécessaire de faire un test pour voir si deux instances de la classes sont égales ?
-
est-il nécessaire de créer une copie de l'instance de la classe ?
-
des opérations sont-elles nécessaire à la classe pour des mécanismes qu'elles utilisent ? Par exemple, un mécanisme
de récupération de place peut avoir besoin qu'un objet distribue toutes ses références à tous les autres
objets, de manière à ce que les ressources non utilisées soient libérées.
Ne définissez pas d'opérations ne faisant que chercher et définir les valeurs des attributs publiques (voir Définition des attributs et Définitions des
associations ). Ils sont en effet générés par les fonctions de génération de code et n'ont pas besoin d'être
définis explicitement.
Utilisez les conventions de dénomination pour le langage d'implémentation lorsque vous nommez des opérations, des types
de retour, des paramètres et leur type. Ils sont décrits dans les Instructions relatives au projet.
Pour chaque opération, vous devez définir les points suivants :
-
Le nom de l'opération - choisissez un nom court et décrivant le résultat que l'opération entraîne.
-
Les noms des opérations doivent avoir la syntaxe du langage d'implémentation. Par exemple :
trouver_emplacement serait correct pour C++ ou Visual Basic, mais pas pour Smalltalk (dans lequel le
soulignement n'est pas utilisé); il vaudrait donc mieux utiliser le nom trouverEmplacement.
-
Eviter les noms qui incluent la façon dont l'opération est réalisée. Par exemple, le nom
Salaires.employés() est meilleur que CalculerSalaires.Employés(), ce dernier indiquant qu'un
calcul est effectué. L'opération peut simplement renvoyer une valeur dans la base de données.
-
Le nom d'une opération doit clairement montrer quel est son but. Eviter les noms trop flous, comme
extraireDonnées, qui ne décrivent pas le résultat que de l'opération. Utilisez un nom indiquant
exactement ce que l'on attend de l'opération comme extraireAdresse. Vous pouvez aussi simplement
donner à l'opération le nom de la propriété renvoyée ou définie. Si elle a un paramètre, le paramètre
définit la propriété. Si elle n'a pas de paramètre, elle extrait la propriété. Par exemple, l'opération
Adresse renvoie l'adresse d'un Client, tandis que adresse(uneChaîne) établit ou change
l'adresse du Client. La nature extraire et établir de l'opération sont implicites dans
la signature de l'opération.
-
Les opérations étant identiques d'un point de vue conceptuel devraient avoir le même nom, même si des
classes différentes les définissent, si elles sont implémentées de manières très distinctes ou si elles
n'ont pas le même nombre de paramètres. Une opération qui crée un objet, par exemple, devrait avoir le même
nom dans toutes les classes.
-
Si les opérations de plusieurs classes ont la même signature,l'opération doit renvoyer le même type de
résultats adaptés à l'objet récepteur. Voici un exemple du concept de polymorphisme indiquant que
plusieurs objets devraient répondre au même message de la même façon. Exemple : l'opération nom doit
renvoyer le nom de l'objet, sans tenir compte de la façon dont le nom est stocké ou dérivé. Suivre ces
principes rend le modèle plus facile à comprendre.
-
Le type de retour - Le type de retour doit correspondre à la classe de l'objet renvoyé par l'opération.
-
Une description courte - Malgré tous vos efforts pour le rendre signifiant, le nom de l'opération n'est
souvent que vaguement utile pour essayer de comprendre ce que l'opération fait. Ecrivez donc, en quelques phrases,
une courte description de l'opération dans la perspective utilisateur de l'opération.
-
Les paramètres - Pour chaque paramètre, créez un nom descriptif, choisissez sa classe et faites-en une brève
description. Lors de la définition des paramètres, rappelez-vous que peu de paramètres impliquent une meilleure
réutilisation. Un petit nombre de paramètres rend l'opération plus facile à comprendre et permet de trouver les
opérations identiques plus facilement. Vous aurez peut-être à diviser une opération ayant beaucoup de paramètres en
plusieurs opérations. L'opération doit être compréhensible pour ceux souhaitant l'utiliser. La description doit
inclure :
-
la signification des paramètres, si on ne peut la connaître à partir de leur nom
-
si le paramètre est transmis par valeur ou par référence
-
des paramètres ayant des valeurs fournies
-
des paramètres optionnels et leur valeur par défaut , si la valeur n'est pas fournie
-
des plages valides pour les paramètres, si possible
-
ce que fait l'opération
-
quels paramètres par référence sont changés par l'opération.
Après avoir défini les opérations, complétez les diagrammes de séquence avec les informations portant sur les
opérations invoquées pour chaque message.
Consultez la section intitulée Instructions relatives au produit : classe de conception pour plus d'informations.
Pour chaque opération, choisissez la visibilité d'exportation de l'opération parmi les possibilités suivantes :
-
Publique - l'opération est visible pour modéliser d'autres éléments que la classe.
-
Implémentation - l'opération n'est visible qu'à l'intérieur de la classe.
-
Protégée - l'opération n'est visible que pour la classe et ses sous-classes ou pour des amis de la
classe (dépendant du langage)
-
Privée - l'opération n'est visible que pour la classe et pour les amis de la classe.
Choisissez la visibilité la plus restrictive possible pouvant accomplir les objectifs de l'opération. Pour cela,
regardez les diagrammes de séquence et déterminez, pour chaque message, s'il vient d'une classe externe au package du
récepteur (demande une visibilité publique), de l'intérieur du package (demande une visibilité
implémentation ), d'une sous-classe (demande la visibilité protégée),de la classe elle-même ou d'un ami
(demande une visibilité privée).
La plupart des opérations sont des opérations d'instances ; cela signifie qu'elles sont exécutées sur les instances de
la classe. Cependant, dans certains cas, une opération s'applique à toutes les instances de la classe. On l'appelle
alors une opération portée classe. Le récepteur de l'opération de la classe est en fait une instance d'une
métaclasse, la description de la classe elle-même, plus qu'une instance spécifique de la classe. Les exemples
d'opérations de classe incluent des messages qui créent (instancient) de nouvelles instances, qui indiquent toutes
les instances d'une classe.
La chaîne de l'opération est soulignée pour indiquer une opération ayant une portée classe.
|
Définition des méthodes
Une méthode définit l'implémentation d'une opération. Dans bien des cas, lorsque le comportement demandé par
l'opération est suffisamment défini par le nom, la description et les paramètres de l'opération, les méthodes sont
implémentées directement dans le langage de programmation. Lorsque l'implémentation d'une opération requiert
l'utilisation d'un algorithme spécifique ou plus d'informations que celle présentées dans la description de
l'opération, une description supplémentaire de la méthode est nécessaire. La méthode décrit la façon dont
l'opération fonctionne, pas seulement ce qu'elle fait.
La méthode doit décrire comment :
-
les opérations seront implémentées
-
les attributs seront implémentés et utilisés pour implémenter les opérations
-
les relations seront implémentées et utilisées pour implémenter les opérations
Les exigences varieront selon les cas, cependant, les spécifications de la méthode d'une classe devraient toujours
indiquer :
-
ce qui sera fait selon les exigences
-
les objets et les opérations qui seront utilisés.
Des exigences plus spécifiques peuvent concerner :
-
la façon dont les paramètres seront implémentés
-
quel algorithme sera utilisé (s'il y en a un).
Les diagrammes de séquence sont une bonne source d'informations. Ils indiquent clairement les opérations qui seront
utilisées dans les autres objets lorsqu'une opération est réalisée. Cette spécification est nécessaire pour
l'implémentation complète de l'opération. La création d'une méthode complète de spécification demande donc
l'identification des opérations pour les objets impliqués et la consultation des diagrammes de séquence correspondants.
|
Définition des états
Pour certaines opérations, leur comportement dépend de l'état dans lequel se trouve l'objet récepteur. Une machine
d'état est un outil qui décrit les états dans lesquels un objet peut être et les événements faisant passer l'objet d'un
état à un autre (voir Technique:
diagramme état-transition ). Les machines d'état sont très utiles pour décrire les classes actives. Il est très
important d'utiliser les machines d'état lors de la définition du comportement desProduit :
Capsules.
La Figure 2 montre un exemple de machine d'état simple.
Figure 2: diagramme état-transition simple d'une pompe à essence
Chaque événement de transition d'état peut être associé à une opération. Selon l'état de l'objet, l'opération peut
avoir un comportement différent. Les événements de transition décrivent comment cela se déroule.
La description de la méthode de l'opération associée doit être mise à jour avec les informations relatives à
l'état, indiquant, pour chaque état pertinent, ce que l'opération doit faire. Les états sont souvent représentés à
l'aide d'attributs ; le diagramme état-transition sert d'entrée dans l'étape d'identification de l'attribut.
Pour obtenir des informations supplémentaires, consultez Technique:
diagramme état-transition.
|
Définition des attributs
Pendant la définition des méthodes et l'identification des états, les attributs dont la classe a besoin
pour effectuer ses opérations sont identifiés. Les attributs fournissent des informations sur le stockage de l'instance
de la classe et sont souvent utilisés pour représenter l'état de l'instance de la classe. Toutes les informations que
la classe gère elle-même sont effectuées par le biais de ses attributs. Pour chaque attribut, définissez :
-
son nom, qui doit respecter les conventions de dénomination du langage d'implémentation et du projet
-
son type, qui sera un type de données élémentaire pris en charge par le langage d'implémentation
-
sa valeur initiale ou par défaut, à laquelle il revient lorsque de nouvelles instances de la classe sont
créées
-
sa visibilité, qui aura une des valeurs suivantes :
-
publique: l'attribut est visible aussi bien à l'intérieur qu'à l'extérieur du package contenant la
classe.
-
protégée: l'attribut n'est visible que pour la classe elle-même, ses sous-classes ou des amis de la
classe.
-
privée: l'attribut n'est visible que pour la classe elle-même et pour les amis de la classe
-
implémentation: l'attribut n'est visible que pour la classe elle-même
-
classes persistantes, si l'attribut est persistant (par défaut) ou transitoire. Même si la classe elle-même
est persistante, tous ses attributs n'ont pas à l'être.
Vérifiez que tous les attribut sont nécessaires. Les attributs doivent être justifiés : il arrive souvent que des
attributs soient ajoutés au début du processus et qu'ils survivent longtemps après qu'ils ne soient plus nécessaires.
Des attributs inutiles, multipliés par des milliers ou des millions d'instances,peuvent avoir un effet négatif sur les
performances et les exigences de stockage d'un système.
Reportez-vous à la section intitulée Attributs dans les Instructions relatives
au produit : classe de conception pour obtenir plus d'informations sur les attributs.
|
Définition des dépendances
A chaque fois que la communication entre des objets est nécessaire, posez-vous les questions suivantes :
-
la référence au récepteur est-elle transmise comme un paramètre à l'opération ? Si c'est le cas, établissez une
dépendance entre les classes de l'expéditeur et du récepteur dans un diagramme de classe contenant les deux
classes. Si le format diagramme de communication est utilisé pour les interactions, définissez la visibilité
du lien et réglez-la sur paramètres.
-
le récepteur est-il global ? Si c'est le cas, établissez une dépendance entre les classes de l'expéditeur et
du récepteur dans un diagramme de classe contenant les deux classes. Si le format diagramme de communication
est utilisé pour les interactions, définissez la visibilité du lien et réglez-la sur global.
-
Le récepteur est-il un objet temporaire créé et détruit pendant l'opération elle-même ? Si c'est le cas, établissez
une dépendance entre les classes de l'expéditeur et du récepteur dans un diagramme de classe contenant les
deux classes. Si le format diagramme de communication est utilisé pour les interactions, définissez la
visibilité du lien et réglez-la la sur local.
Notez que les liens modélisés de cette façon sont des liens transitoires, n'existant que pour une durée limitée dans le
contexte de la collaboration. En cela, ces liens sont des instances du rôle de l'association dans la collaboration.
Toutefois, la relation dans un modèle de classe (c'est-à-dire en dehors du contexte) doit être une dépendance, comme
nous l'avons dit auparavant. Comme c'est écrit dans[RUM98], dans la
définition du lien transitoire: "Il est possible de modéliser des liens comme des associations, mais les
conditions des associations doivent dans ce cas être établies de manière très large. Elles perdent alors beaucoup de
leur précision en contraignant des combinaisons d'objets". Dans cette situation, la modélisation d'une dépendance est
moins importante que la modélisation de la relation dans la collaboration, car la dépendance ne décrit pas complètement
la relation, elle spécifie juste qu'elle existe.
|
Définition des associations
Les associations fournissent aux objets les mécanismes pour communiquer entre eux. Elles leur fournissent un canal dans
lequel les messages peuvent circuler. Elles indiquent aussi les dépendances entre classes, soulignant que des
changements effectués dans une classe peuvent être ressentis dans beaucoup d'autres classes.
Examinez les descriptions de la méthode pour chaque opération afin de comprendre comment les instances de la
classe communiquent et collaborent avec d'autres objets. Pour envoyer un message à un autre objet, un objet doit avoir
une référence au récepteur du message. Un diagramme de communication (une alternative au diagramme de séquence)
représentera la communication entre objets en termes de liens, comme le montre la Figure 3.
Figure 3: Exemple d'un diagramme de communication
Les messages restants utilisent soit l'association, soit l'agrégation pour définir la relation entre les
instances de deux classes qui communiquent. Voir Technique:
Association et Technique: Agrégation pour obtenir des informations concernant le choix des
représentations. Pour ces deux associations, définissez la visibilité du lien et réglez-la sur champ dans les
diagrammes de communication. Pour les autres tâches il faut :
-
établir la navigabilité des associations et des agrégations. Vous pouvez faire cela en observant les navigabilités
requises sur leurs instanciations de lien dans les diagrammes d'interaction. La navigabilité étant vérifiée
par défaut, vous devez trouver les associations (et les agrégations) où tous les rôles de lien opposés de tous les
objets d'une classe dans l'association n'ont pas besoin de navigabilité. Il faut alors régler la navigabilité sur
non vérifiée dans le rôle de la classe.
-
S'il y a des attributs dans l'association elle-même (représentés par des classes d'association), créez une classe
de conception pour représenter la classe d'association avec les attributs appropriés. Placez cette classe entre
deux autres classes et établissez des associations, avec le multiplicité qui convient, entre la classe
d'association et les deux autres classes.
-
Définissez si la terminaison de lien doit être commandée ou non ; c'est le cas lorsque des objets
associés à un objet à l'autre extrémité de l'association ont un classement devant être conservé.
-
Si n'y a que la classe actuelle qui fait référence à la classe associée ou agrégée, réfléchissez si la classe doit
être imbriquée ou non. Les classes imbriquées permettent une messagerie plus rapide et un modèle de conception plus
simple. Ces classes ont aussi des inconvénients : l'espace de la classe imbriquée est attribué de manière statique,
sans tenir compte du fait qu'il y ait ou non des instances de la classe imbriquée, le manque d'identité de l'objet
en dehors de la classe d'encapsulation et l'incapacité de pointer sur les instances des classes imbriquées à
l'extérieur de la classe d'encapsulation.
Les associations et les agrégations sont mieux définies dans un diagramme de classe décrivant les classes associées. Le
diagramme de classe doit être possédé par le package contenant les classes associées. La Figure 4 montre un
exemple de diagramme de classe, décrivant les associations et les agrégations.
Figure 4: Exemple d'un diagramme de classe montrant les associations, les agrégations et les généralisations entre
classes.
Les associations d'abonnement entre des classes d'analyse sont utilisées pour identifier ces dépendances
d'événements entre des classes. Dans le modèle de conception, vous devez traiter ces dépendances d'événements
explicitement, soit en utilisant des infrastructures gestionnaires d'événements, soit en créant votre propre
infrastructure gestionnaire d'événements. Dans certains langages de programmation, comme Visual Basic, cela se fait de
façon directe ; vous déclarez, mettez au point et gérez les événements correspondants. Dans d'autres langages, vous
pouvez avoir à utiliser des bibliothèques supplémentaires de fonctions réutilisables pour traiter les abonnements et
les événements. Si la fonctionnalité n'est pas fournie, il faudra la conceptualiser et la construire. Voir également Technique: association d'abonnement.
|
Définition de la structure interne
Certaines classes peuvent représenter des abstractions complexes et avoir une structure complexe. Lors de la
modélisation, le concepteur peut souhaiter représenter ses éléments participants internes et leurs relations pour être
sûr que l'implémenteur implémentera les collaborations ayant lieu à l'intérieur de la classe en fonction de cela.
Dans UML 2.0, les classes sont définies comme des classes
structurées, ayant la capacité d'avoir une structure et des ports internes. Ensuite, les classes peuvent être
décomposées en séries de parties connectées qui peuvent, à leur tour, être décomposées. Une classe peut être encapsulée
en forçant des communications externes à passer par des ports obéissants aux interfaces déclarées.
Lorsque vous trouvez une classe complexe avec une structure complexe, créez un diagramme de structure composite pour
cette classe. Modélisez les parties qui accompliront les rôles de ce comportement de la classe. Etablissez la façon
dont les parties sont "liées" en utilisant des connecteurs. Utilisez des ports avec des interfaces déclarées si vous
voulez permettre à plusieurs clients de cette classe d'accéder à certaines parties du comportement offert par cette
classe. Utilisez aussi des ports pour isoler complètement les parties internes de cette classe vis à vis de
l'environnement.
Pour obtenir plus d'informations sur ce sujet, ainsi que des exemples de diagramme de structure composite, voir aussi
Concept : classe structurée.
|
Définition des généralisations
Les classes peuvent être organisées selon une hiérarchie de généralisation pour refléter les structures et les
comportements communs. Une superclasse commune peut être définie, les sous-classes peuvent hériter de son
comportement et de sa structure. La généralisation vous permet de définir une structure et un comportement communs à un
emplacement particulier et de les réutiliser lorsque vous trouvez des comportements et des structures répétitives.
Consultez Technique : généralisation pour plus d'informations sur les relations de
généralisation.
Lorsque vous trouvez une généralisation, créez une superclasse commune pour contenir les attributs, les associations,
les agrégations et les opérations en commun. Supprimer les comportements en commun des classes qui deviendront des
sous-classes de la superclasse commune. Définissez une relation de généralisation de la sous-classe vers la
superclasse.
|
Résolution des collisions entre cas d'utilisation
Le but de cette étape est d'éviter les conflits d'accès concurrent qui ont lieu lorsque deux classes ou plus tentent
d'accéder à des instances de la classe de conception au même moment, parfois de manière incohérente.
Un des problèmes posés par le fait de procéder cas d'utilisation par cas d'utilisation lors du processus de conception,
est que deux cas d'utilisation ou plus peuvent essayer d'appeler des opérations simultanément sur des objets de
conception et parfois de manière conflictuelle. Lorsque c'est le cas, les conflits d'accès concurrent doivent être
identifiés et résolus de manière explicite.
Si une messagerie synchrone est utilisée, la réalisation d'une opération bloquera les appels ultérieurs jusqu'à ce que
l'opération soit terminée. Une messagerie synchrone implique un ordre de traitement des messages du type "premier
arrivé, premier servi". Cela peut résoudre le conflit d'accès concurrent, spécialement dans les cas où tous les
messages ont la même priorité ou lorsque chaque message utilise la même unité d'exécution. Lorsque l'on peut accéder à
un objet grâce à plusieurs unités d'exécution (représentées par des classes actives), des mécanismes explicites doivent
être utilisés pour éviter ou pour résoudre les conflits d'accès concurrent.
Dans les systèmes en temps réel où les unités d'exécution sont représentées par des Produit :
capsules, ce problème doit cependant être résolu pour les accès concurrents multiples aux objets passifs, tandis
que les capsules fournissent elles-mêmes un mécanisme de file d'attente et obligent la sémantique d'exécution à traiter
les accès concurrents. Il est conseillé d'encapsuler les objets passifs dans les capsules, cela évite les problèmes
d'accès concurrent dans la sémantique de la capsule.
Plusieurs opérations d'un même objet peuvent être appelées simultanément par différentes unités d'exécution, sans
entraîner de conflit d'accès concurrent ; par exemple, le nom et l'adresse d'un client peuvent être modifiés au même
moment sans créer de conflit. C'est seulement lorsque deux unités d'exécution tentent de modifier la même propriété de
l'objet qu'un conflit a lieu.
Pour chaque objet auquel plusieurs unités d'exécution peuvent accéder, identifiez les sections de code devant être
protégées des accès simultanés. Il est impossible d'identifier les segments du code spécifique plus tôt dans la phase
d'élaboration ; les opérations devant être protégées suffiront. Ensuite, sélectionnez ou créez des mécanismes de
contrôle d'accès appropriés pour éviter les conflits d'accès simultané. Ces mécanismes contiennent des messages de mise
en file d'attente pour sérialiser l'accès, des sémaphores ou des jetons pour autoriser l'accès à une seule unité
d'exécution à la fois ou d'autres variantes de mécanismes de fermeture. Le choix du mécanisme dépend beaucoup de
l'implémentation et change en fonction du langage de programmation et de l'environnement d'exploitation. Voir les Instructions relatives au projet pour avoir des conseils sur le choix
des mécanismes d'accès concurrent.
|
Gestion des exigences non fonctionnelles générales
Les classes de conception sont faites pour traiter les exigences non fonctionnelles et générales. Il est donc important
lors de cette étape qu'une classe d'analyse ait des exigences non fonctionnelles, qui peuvent déjà être établies dans
ses exigences et responsabilités particulières. De telles exigences sont souvent définies en termes des mécanismes
architecturaux (d'analyse) nécessaires à la réalisation de la classe. Lors de cette étape, la classe est donc affinée
pour introduire les mécanismes de conception correspondant à ces mécanismes d'analyse.
Les mécanismes de conception disponibles sont identifiés et définis par l'architecte du logiciel. Pour chaque mécanisme
de conception nécessaire, définissez autant de caractéristiques possibles, en les classant s'il le faut. Pour plus
d'informations sur les mécanismes de conception ,consultez Tâche :
identification des mécanismes de conception, Concept :
mécanismes d'analyse et Concept: mécanismes de conception et d'implémentation .
Il peut y avoir plusieurs instructions et mécanismes de construction générales devant être pris en compte lors de la
conception des classes, comme par exemple comment :
-
utiliser les produits et les composants existants
-
adapter le langage de programmation
-
distribuer les objets
-
obtenir des performances acceptables
-
obtenir un certain niveau de sécurité
-
traiter les erreurs
|
Evaluation de vos résultats
A ce stade, vous devez évaluer votre modèle de conception afin de vous assurer que votre travail semble correct. Il
n'est pas nécessaire de revoir votre modèle en détail, mais vous devez prendre en considération les listes de contrôle
suivantes :
|
|