Objet
  • Garantir que la classe fournisse le comportement requis par les réalisations de cas d'utilisation.
  • S'assurer que les informations sont suffisantes pour une implémentation sans ambiguïté de la classe.
  • Traiter les exigences non fonctionnelles associées à la classe.
  • Incorporer les mécanismes de conception utilisés par la classe.
Rôle :  Concepteur 
Fréquence : une fois par itération. 
Etapes
Artefacts d'entrée :    Artefacts de sortie :   
Guides d'utilisation de l'outil :   
Plus d'informations : 

Détail de l'enchaînement d'activités :   

Les classes sont les chevilles ouvrières de l'activité de conception : elles réalisent le travail véritable dans le système. D'autres éléments de conception, comme les sous-systèmes, packages et collaborations, décrivent le regroupement ou l'interopération des classes.

Les classes actives sont des classes de conception qui coordonnent et dirigent le comportement des classes passives : une classe active est une classe dont les instances sont des objets actifs, propriétaires de leurs propres fils de contrôle.

Utilisation de patterns et de mécanismes de conceptionHaut de la page

Utilisez les patterns et les mécanismes de conception comme approprié à la classe ou à la capacité à développer, et en conformité avec les principes de conception du projet.

L'incorporation d'un pattern ou d'un mécanisme a pour effet de réaliser concrètement plusieurs des étapes ultérieures de cette activité (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 mécanismes sont généralement incorporés au fur et à mesure de l'évolution de la conception et non pas en tant que première étape de cette activité. Ils sont aussi fréquemment appliqués à un groupe de classes, plutôt qu'à une classe unique.

Création de classes de conception initiales Haut de la page

Créez une ou plusieurs classes de conception initiales pour la classe d'analyse fournie comme entrée de cette activité et affectez-leur des dépendances de trace. Les classes de conception créées lors de cette étape seront affinées, ajustées, fractionnées ou fusionnées au cours d'étapes ultérieures lorsque diverses propriétés de conception décrivant la conception de la classe d'analyse leur seront affectées (comme des opérations, méthodes et un automate à états).

Selon le type de classe d'analyse (limite, entité ou contrôle) envisagé, vous pouvez utiliser des stratégies spécifiques pour créer vos classes de conception initiales.

Conception de classes limites

Les classes limites représentent des interfaces avec des utilisateurs ou avec d'autres systèmes.

Généralement, les classes limites représentant des interfaces avec d'autres systèmes sont modélisées en tant que sous-systèmes vu qu'elles comportent souvent un comportement interne complexe. Si le comportement de l'interface est simple (agissant par exemple uniquement comme passe-système vers une API existante du système externe), vous pouvez choisir de la représenter à l'aide d'une ou de plusieurs classes de conception. Dans ce cas, utilisez une classe de conception unique par protocole, interface, ou API, et notez les exigences spéciales concernant les normes utilisées dans les exigences spéciales de la classe.

Les classes limites représentant des interfaces vers les utilisateurs suivent généralement la règle selon laquelle une classe est dédiée à chaque fenêtre ou à chaque formulaire de l'interface utilisateur. Par conséquent, les responsabilités des classes limites peuvent être définies à un niveau relativement abstrait et doivent être élaborées et détaillées dans cette étape. Vous pouvez aussi envisager d'utiliser d'autres modèles et prototypes d'interface utilisateur dans cette étape.

La conception des classes limites dépend des outils de développement de l'interface utilisateur disponibles pour le projet. A l'aide des technologies actuelles, il est courant que l'interface utilisateur soit construite visuellement, directement dans l'outil de développement. Des classes de l'interface utilisateur sont ainsi créées automatiquement et doivent être associées à la conception des classes de contrôle et d'entités. Si l'environnement de développement de l'interface utilisateur crée automatiquement les classes de support requises pour implémenter cette interface, vous n'avez pas en prendre en compte ces classes pour la conception. Vous n'avez à concevoir que les éléments qui ne sont pas créés pour vous par l'environnement de développement.

Conception de classes d'entités

Les classes d'entités représentent les unités d'information manipulées lors de l'analyse. Elles sont souvent passives et persistantes et peuvent être identifiées et associées au mécanisme d'analyse pour persistance. Les rouages de la conception d'un mécanisme de persistance basée base de données sont couverts dans la section Activité : Conception de la base de données. Des considérations de performances peuvent vous forcer à effectuer un réusinage des classes persistantes, provoquant des modifications du modèle de conception (discutées conjointement dans Rôle : Concepteur de base de données et Rôle : Concepteur).

Une discussion plus approfondie des questions de conception pour les classes persistantes est présentée plus loin sous la rubrique Identification des classes persistantes.

Conception des classes de contrôle

Un objet de contrôle est responsable de la gestion du flux d'un cas d'utilisation et, par conséquent, coordonne la plupart de ses actions. Les objets de contrôle encapsulent la logique qui n'est pas directement associée aux aspects de l'interface utilisateur (objets limites) ou d'ingénierie des données (objets entités). Cette logique est parfois dénommée logique applicative ou logique métier.

Prenez en compte les aspects suivants lors de la conception de classes de contrôle :

  • Complexité - Vous pouvez gérer un comportement de contrôle ou de coordination non complexe à l'aide de classes d'entités ou limites. Lorsque la complexité de l'application s'accroît, des inconvénients sérieux de cette approche émergent, comme :
  • Le comportement de coordination du cas d'utilisation devient imbriqué dans l'interface utilisateur, rendant plus difficile toute modification du système.
  • La même interface utilisateur ne peut pas être utilisée sans difficultés dans des réalisations de cas d'utilisation différentes.
  • L'interface utilisateur est alourdie par des fonctionnalités supplémentaires, ce qui dégrade ses performances.
  • Les objets entités peuvent être grevés par un comportement spécifique à un cas d'utilisation, ce qui réduit leur généralité.

Pour éviter ces problèmes, des classes de contrôle sont introduites afin de fournir le comportement associé à la coordination des flux d'événements.

  • Probabilité de modification - Si la probabilité de modification des flux d'événements est faible ou que son coût est négligeable, les dépenses supplémentaires et la complexité associées à des classes de contrôle additionnelles peuvent ne pas être justifiées.
  • Distribution et performances - La nécessité d'exécuter diverses parties de l'application sur des noeuds différents, ou dans des espaces de processus distincts, induit un besoin de spécialisation des éléments du modèle de conception. Cette spécialisation est souvent accomplie par l'ajout d'objets de contrôle et la distribution du comportement des classes limites et d'entités entre des classes de contrôle. Ce faisant, les classes limites en viennent à se cantonner à fournir des services d'interface utilisateur purs, les classes d'entités des services de données, et les classes de contrôle le reste.
  • Gestion des transactions - La gestion des transactions constitue une activité de coordination classique. En l'absence d'un cadre dédié à cette gestion, une ou plusieurs classes de gestionnaire de transaction devraient interagir pour garantir le maintien de l'intégrité des transactions.

Dans les deux derniers cas, si la classe de contrôle représente un fil de contrôle séparé, il peut être préférable d'utiliser une classe active pour modéliser le fil de contrôle.

Identification des classes persistantesHaut de la page

Les classes devant stocker leur état sur un support permanent sont dénommées persistantes. Cette mémorisation de leur état peut répondre à un besoin d'enregistrement permanent des informations de classe, de sauvegarde en cas d'échec du système, ou d'échange d'informations. Une classe persistante peut comporter à la fois des instances persistantes et temporaires. La désignation d'une classe en tant que telle signifie simplement que certaines instances de la classe peuvent devoir être persistantes.

Incorporez les mécanismes de conception correspondant aux mécanismes de persistance détectés lors de l'analyse. En fonction des besoins de la classe, le mécanisme d'analyse de la persistance pourrait par exemple être réalisé par l'un des mécanismes de conception suivants :

  • Stockage en mémoire
  • Carte mémoire Flash
  • Fichier binaire
  • Système de gestion de base de données (SGBD)

Les objets persistants peuvent ne pas être dérivés seulement des classes d'entités. Ces objets peuvent aussi être requis pour traiter des exigences non fonctionnelles générales. Il peut s'agir, par exemple, d'objets persistants servant à conserver les informations relatives au contrôle de processus ou les informations d'état entre transactions.

L'identification des classes persistantes sert à aviser le Rôle : Concepteur de base de données que les caractéristiques de stockage physique de la classe requièrent une attention spéciale. Elle informe également le Rôle : Architecte logiciel que la classe doit être persistante et le Rôle : Concepteur responsable du mécanisme de persistance que les instances de la classe doivent être rendues persistantes.

En raison de la nécessité d'une stratégie de persistance coordonnée, le Rôle : Concepteur de base de données est responsable du mappage des classes persistantes dans la base de données, à l'aide d'une structure de persistance. Si le projet est amené à développer une structure de persistance, son développeur aura aussi à charge de déterminer les exigences des classes de conception en matière de persistance. Il suffit à ce stade, pour que ces personnes disposent des informations requises, d'indiquer que la classe est persistante, ou, plus exactement, que les instances de la classe le sont.

Définition de la visibilité de classe Haut de la page

Définissez la visibilité de chaque classe dans le package où elle réside. Une classe publique peut être référencée en dehors du package qui la contient. Une classe privée (ou dont la visibilité est définie à implémentation) ne peut être référencée que par des classes du même package.

Définition des opérations Haut de la page

Identification des opérations

Pour identifier les opérations sur les classes de conception, procédez comme suit :

  • Etudiez 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 description initiale de l'opération.
  • Etudiez les réalisations de cas d'utilisation auxquelles participe la classe pour établir comment les opérations sont employées par les cas d'utilisation. Développez les opérations, une réalisation de cas d'utilisation à la fois, en affinant les opérations, leurs descriptions, types de retour et paramètres. Les exigences de chaque réalisation de cas d'utilisation sont décrites dans le flux d'événements de la réalisation correspondante.
  • Etudiez les exigences spéciales du cas d'utilisation pour vous assurer de ne pas omettre d'exigences implicites sur l'opération pouvant être mentionnées ici.

Des opérations sont requises pour prendre en charge les messages apparaissant dans les diagrammes de séquence car des scripts (spécifications de messages temporaires n'ayant pas encore été affectées aux opérations) décrivent le comportement que la classe est censée concrétiser. Un exemple de diagramme de séquence est illustré à la Figure 1.

Diagramme décrit dans le texte d'accompagnement.

Figure 1 : Les messages forment la base de l'identification des opérations

Les réalisations de cas d'utilisation ne peuvent pas fournir assez d'informations pour identifier toutes les opérations. Pour déterminer les opérations restantes, posez-vous les questions suivantes :

  • Est-il possible d'initialiser une nouvelle instance de la classe, y compris en la connectant à des instances d'autres classes auxquelles elle est associée ?
  • Un test est-il nécessaire pour établir si deux instances de la classe sont égales ?
  • Est-il nécessaire de créer une copie d'une instance de classe ?
  • Des opérations sur la classe sont-elles requises par des mécanismes qu'elle utilise ? Par exemple, un mécanisme de nettoyage peut imposer qu'un objet soit capable de se défaire de toutes ses références à d'autres objets afin que les ressources inutilisées puissent être libérées.

Ne définissez pas d'opérations se contentant d'acquérir et de définir les valeurs d'attributs publics (voir Définition d'attributs et Définition d'associations ). Elles sont habituellement générées par des utilitaires de génération de code et n'ont pas à être définies explicitement.

Nommage et description des opérations

Utilisez les conventions d'attribution de noms du langage d'implémentation lorsque vous devez nommer des opérations, des types de retours, des paramètres et leurs types.

Pour chaque opération, vous devez définir les points suivants :

  • Le nom de l'opération - utilisez un nom court et révélateur des résultats de l'opération.
    • Les noms d'opération doivent suivre la syntaxe du langage d'implémentation. Exemple : recherche_emplacement pourrait être acceptable pour C++ ou Visual Basic, mais non pas pour for Smalltalk (qui n'utilise pas les caractères de soulignement) ; le nom rechercheEmplacement serait préférable.
    • Evitez les noms qui suggèrent comment l'opération est effectuée. Par exemple, salaires.Employes() est préférable à calculSalaires.Employes() car ce dernier sous-entend qu'un calcul est effectué. L'opération peut se borner à retourner une valeur contenue dans la base de données.
    • Le nom d'une opération doit présenter clairement son objectif. Evitez les noms vagues, comme acquisitionDonnees, qui ne décrivent pas le résultat qu'ils renvoient. Utilisez un nom exposant exactement le résultat attendu, comme acquisitionAdresse. Mieux encore, adoptez comme nom de l'opération celui de la propriété retournée ou définie. S'il est assorti d'un paramètre, ce nom définit la propriété. S'il ne comporte pas de paramètre, il obtient cette propriété. Exemple : l'opération adresse renvoie l'adresse d'un Client, tandis que adresse(chaîne) définit ou modifie l'adresse du Client. La nature de l'opération, get (acquisition) ou set (définition) est implicite d'après la signature de l'opération.
    • Les opérations conceptuellement identiques doivent porter le même nom, même si des classes différentes les définissent, quand bien même elles seraient implémentées de manière totalement différente ou comporteraient un nombre de paramètres différent. Une opération qui crée un objet, par exemple, doit porter le même nom dans toutes les classes.
    • Si des opérations de plusieurs classes ont la même signature, elles doivent retourner le même type de résultat (adapté à l'objet récepteur). Ceci découle du concept de polymorphisme, qui stipule que des objets différents doivent répondre de manière similaire à un message identique. Exemple : l'opération nom doit retourner le nom de l'objet, quelque soit la manière dont celui-ci soit stocké ou dérivé. Le respect de ce principe facilite la compréhension du modèle.
  • Le type de retour - Le type de retour doit être la classe d'objet retournée par l'opération.
  • Une brève description - Aussi évocateur qu'il soit, le nom de l'opération ne donne souvent qu'une indication vague du but de l'opération. Ajoutez à l'opération une brève description composée de quelques lignes et rédigée depuis la perspective de son utilisateur.
  • Les paramètres - Pour chaque paramètre, créez un nom descriptif concis, décidez de sa classe, et ajoutez-lui une brève description. En spécifiant les paramètres, rappelez-vous que moins nombreux ils seront et meilleure sera la capacité de réutilisation de l'opération. Un petit nombre de paramètres rend l'opération plus facile à comprendre et, par conséquent, rend plus probable la détection d'opérations similaires. Vous pouvez avoir à scinder en plusieurs opérations une opération comportant un grand nombre de paramètres. L'opération doit être intelligible pour ceux qui voudraient l'utiliser. La brève description doit inclure :
    • La signification des paramètres, si elle n'est pas évidente d'après leur nom.
    • Si le paramètre est passé par valeur ou par référence.
    • Les paramètres dont la valeur doit être fournie.
    • Les paramètres facultatifs et leurs valeurs par défaut lorsque aucune valeur n'est spécifiée.
    • Les plages de valeurs valides pour les paramètres, le cas échéant.
    • Ce qu'effectue l'opération.
    • Quels sont les paramètres par référence modifiés par l'opération.

Après avoir défini les opérations, complétez les diagrammes de séquence avec les informations sur les opérations appelées pour chaque message.

Pour plus d'informations, reportez-vous à la section intitulée Opérations de classes dans Principes et conseils : Classe de conception.

Définition de la visibilité des opérations

Définissez la visibilité à l'exportation de chaque opération d'après l'une des options suivantes :

  • Publique - l'opération est visible par les éléments du modèle autres que la classe elle-même.
  • 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 par la classe elle-même, ses sous-classes, ou ses classes amies (suivant le langage).
  • Privée - l'opération n'est visible que par la classe elle-même et par ses classes amies.

Sélectionnez la visibilité la plus restreinte possible pouvant accomplir les objectifs de l'opération. Pour ce faire, observez les diagrammes de séquence et, pour chaque message, déterminez s'il provient d'une classe hors du package du récepteur (requiert alors une visibilité publique), à l'intérieur du package (requiert une visibilité implémentation), d'une sous-classe (requiert une visibilité protégée), ou de la classe elle-même ou d'une classe amie (requiert une visibilité privée).

Définition des opérations de classe

Pour la plupart, les opérations sont des opérations d'instance, c'est-à-dire qu'elles sont effectuées sur des instances de la classe. Dans certains cas cependant, une opération s'applique à toutes les instances de la classe et constitue alors une opération avec portée sur la classe. Le récepteur de l'opération de classe est en fait une instance d'une métaclasse (la description de la classe elle-même) au lieu d'une instance spécifique de la classe. Les opérations de classe incluent les messages qui créent (instancient) de nouvelles instances, qui retournent toutes les instances d'une classe (allInstances) et ainsi de suite .

La chaîne d'opération est soulignée pour dénoter qu'il s'agit d'une opération avec portée sur la classe.

Définition des méthodes Haut de la page

Une méthode spécifie l'implémentation d'une opération. Dans les nombreux cas où le comportement requis par l'opération est suffisamment défini par son nom, sa description et ses paramètres, les méthodes sont implémentées directement dans le langage de programmation. Lorsque l'implémentation d'une opération nécessite l'utilisation d'un algorithme ou des informations absentes de sa description, une description de méthode séparée est requise. La méthode ne décrit pas seulement ce que fait l'opération mais aussi comment elle s'y prend.

Si elle est décrite, la méthode doit expliquer :

  • Comment les opérations seront implémentées.
  • Comment les attributs seront implémentés et utilisés pour implémenter des opérations.
  • Comment les relations seront implémentées et utilisées pour implémenter des opérations.

Les exigences varient d'un cas à l'autre. Cependant, les spécifications d'une méthode pour une classe doivent toujours stipuler :

  • Ce qui sera exécuté en vertu des exigences.
  • Les autres objets qui seront utilisés, et leurs opérations.

Des exigences plus spécifiques peuvent détailler les points suivants :

  • Comment les paramètres seront implémentés.
  • Les algorithmes spéciaux à utiliser, le cas échéant.

Les diagrammes de séquence sont une source précieuse pour cette description. Ces diagrammes élucident les opérations qui seront utilisées dans d'autres objets lorsqu'une opération est effectuée. Cette spécification est nécessaire pour l'implémentation complète d'une opération. La production d'une spécification de méthode complète requiert, par conséquent, d'identifier les opérations des objets impliqués et d'examiner les diagrammes de séquence correspondants.

Définition des étatsHaut de la page

Le comportement de certaines opérations est fonction de l'état de leur objet récepteur. Un automate à états est un outil qui décrit les états pouvant être assumés par un objet et les événements conduisant cet objet à passer à un autre état (voir Principes et conseils : Diagrammes d'état-transition). Les automates à états sont particulièrement utiles pour décrire des classes actives.

La Figure 2 propose un exemple d'automate à états simple.

Diagramme décrit dans le texte d'accompagnement.

Figure 2 : Diagramme d'état-transition simple pour un distributeur de carburant

Chaque événement de transition d'état peut être associé à une opération. L'opération peut avoir un comportement différent selon l'état de l'objet et les événements de transition expliquent comment ceci se produit.

La description de la méthode pour l'opération associée doit être mise à jour avec les informations d'état spécifiques, indiquant pour chaque état pertinent ce que doit accomplir l'opération. Les états sont souvent représentés à l'aide d'attributs ; les diagrammes d'état-transition servent d'entrée pour l'étape d'identification d'attribut.

Pour plus d'information, voir Principes et conseils : Diagramme d'état-transition.

Définir des attributs Haut de la page

Les attributs requis par la classe pour réaliser ses opérations sont déterminés lors de la définition des méthodes et l'identification des états. Les attributs assurent le stockage des informations de l'instance de classe et sont souvent utilisés pour représenter son état. Les informations conservées par la classe elle-même sont préservées à l'aide de ses attributs. Vous devez définir pour chaque attribut :

  • Son nom, qui doit respecter à la fois les conventions d'attribution de nom du langage et celles du projet.
  • Son type, qui sera un type de données élémentaire pris en charge par le langage d'implémentation.
  • Sa valeur par défaut, ou initiale, selon laquelle il sera initialisé lors de la création de nouvelles instances de la classe.
  • Sa visibilité, qui peut recevoir l'une des valeurs suivantes :
    • Publique : l'attribut est visible à l'intérieur et à l'extérieur du package contenant la classe.
    • Protégée : l'attribut est uniquement visible par la classe, ses sous-classes ou ses classes amies (suivant le langage).
    • Privée : l'attribut n'est visible que par la classe elle-même et par ses classes amies.
    • Implémentation : l'attribut est visible uniquement par la classe elle-même.
  • Pour les classes persistantes, que l'attribut soit persistant (par défaut) ou temporaire, bien que la classe elle-même puisse être persistante, la persistance n'est pas requise de tous ses attributs.

Vérifiez que tous les attributs sont effectivement requis. Les attributs doivent être justifiés : il est possible que certains aient été ajoutés au début du processus et conservés bien qu'ils n'aient plus d'utilité, par manque de perspective. Les attributs superflus, multipliés par des milliers ou des millions d'instances, peuvent avoir un effet négatif sur les performances et les besoins de stockage d'un système.

Pour plus d'informations sur ce sujet, reportez-vous à la section intitulée Attributs dans Principes et conseils : Classe de conception.

Définition des dépendances Haut de la page

Pour chaque cas où la communication entre objets est requise, élucidez les questions suivantes :

  • La référence au récepteur est-elle passée à l'opération en tant que paramètre ? Dans ce cas, établissez une dépendance entre l'émetteur et le récepteur dans un diagramme de classe contenant les deux classes. De plus, si le format du diagramme de communication est utilisé pour les interactions, qualifiez la visibilité du lien et définissez-la à paramètre.
  • S'agit-il d'un récepteur global ? Dans ce cas, établissez une dépendance entre la classe de l'émetteur et celle du récepteur dans un diagramme de classe contenant les deux classes. De plus, si le format du diagramme de communication est utilisé pour les interactions, qualifiez la visibilité du lien et définissez-la à globale.
  • Le récepteur est-il un objet temporaire créé et détruit au cours même de l'opération ? Dans ce cas, établissez une dépendance entre la classe de l'émetteur et celle du récepteur dans un diagramme de classe contenant les deux classes. De plus, si le format du diagramme de communication est utilisé pour les interactions, qualifiez la visibilité du lien et définissez-la à locale.

Notez que les liens modélisés de cette manière sont transitoires (n'existent que pour une durée limitée et dans le contexte spécifique de la collaboration) et sont, en ce sens, des instances du rôle d'association dans la collaboration. Cependant, la relation dans un modèle de classes (c'est-à-dire indépendant du contexte) doit constituer une dépendance, comme mentionné auparavant. Comme stipulé dans [RUM98], dans la définition de lien transitoire : "Il est possible de modéliser tous les liens de ce type en tant qu'associations, auquel cas les conditions affectant les associations doivent être énoncées de manière très générale et au prix d'une perte de précision importante quant aux contraintes affectant les combinaisons d'objets." Dans cette situation, la modélisation d'une dépendance est moins importante que celle de la relation dans la collaboration, étant donné que la dépendance ne décrit pas complètement la relation mais seulement son existence.

Définition des associations Haut de la page

Les associations fournissent un mécanisme permettant aux objets de communiquer entre-eux. Elles fournissent aux objets un conduit où les messages peuvent circuler. Elles documentent également les dépendances entre classes, soulignant que les modifications apportées à une classe devraient être ressenties dans de nombreuses autres classes.

Examinez les descriptions de méthode de 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 disposer d'une référence au récepteur du message. Un diagramme de communication (représentation alternative d'un diagramme de séquence) présente les communications de l'objet en termes de liens, comme illustré à la Figure 3.

Diagramme décrit dans le texte d'accompagnement.

Figure 3 : Exemple de diagramme de communication

Définition des associations et des agrégations

Les messages restants utilisent une association, ou bien une agrégation, pour spécifier la relation entre les instances de deux classes qui communiquent. Voir Principes et conseils : Association et Principes et conseils : Agrégation pour plus d'indications sur la sélection de la représentation adéquate. Pour ces deux associations, définissez la visibilité du lien à zone dans les diagrammes de communication. Il convient ensuite de compléter les tâches suivantes :

  • Etablissement de la navigabilité des associations et des agrégations. Pour ce faire, vous pouvez analyser la navigabilité requise sur les instanciations de liens depuis les diagrammes d'interaction. Comme la navigabilité est définie par défaut à true (vrai), il vous suffit de dépister les associations (et agrégations) où tous les rôles de lien réciproques de tous les objets d'une classe dans l'association ne requièrent pas de navigabilité. Pour ces cas, définissez la navigabilité à false (faux) sur le rôle de la classe.
  • Si l'association elle-même comporte des attributs (représentées par des classes d'association), créez une classe de conception représentant la classe d'association, avec les attributs adéquats. Interposez cette classe entre les deux autres et établissez des associations avec la multiplicité appropriée entre la classe d'association et les deux autres.
  • Spécifiez si les terminaisons d'associations doivent être ordonnées ou non. Ceci est le cas lorsque l'ordre des objets associé à un objet à l'autre extrémité de l'association doit être préservé.
  • Si la classe associée (ou agrégée) n'est référencée que par la classe actuelle, déterminez si elle doit être imbriquée. Les avantages de cette pratique tiennent à ce qu'elle permet un échange de messages plus rapide et un modèle de conception plus simple. Ses inconvénients sont les suivants : espace dédié à la classe imbriquée alloué de manière statique (que des instances de cette classe existent ou non), absence d'une identité d'objet distincte de celle de la classe qui l'englobe ou incapacité à référencer les instances de la classe imbriquée en dehors de celle qui l'englobe.

Il est préférable de définir les associations et les agrégations dans un diagramme de classes décrivant les classes associées. Ce diagramme doit être la propriété du package contenant les classes associées. La Figure 4 illustre un exemple d'un tel diagramme, décrivant les associations et agrégations.

Diagramme décrit dans le texte d'accompagnement.

Figure 4 : Exemple de diagramme de classe présentant les associations, agrégations et généralisations entre classes

Traitement des associations de souscription

Les associations de souscription entre classes d'analyse sont utilisées pour identifier des dépendances d'événements entre classes. Dans le modèle de conception, vous devez traiter ces dépendances d'événements explicitement, soit en utilisant les structures de gestionnaires d'événements disponibles, soit en concevant et en créant la votre. Sous certains langages de programmation (comme Visual Basic), ceci ne présente pas de difficulté particulière : vous n'avez qu'à déclarer, invoquer et gérer les événements correspondants. Sous d'autres langages, vous pouvez devoir utiliser une bibliothèque complémentaire de fonctions réutilisables pour gérer les souscriptions et les événements. Si vous ne pouvez pas acquérir la fonctionnalité requise, vous devrez la concevoir et la construire. Voir aussi Principes et conseils : Association de souscription.

Définition de la structure interne Haut de la page

Certaines classes peuvent représenter des abstractions complexes et comporter une structure complexe. Lors de la modélisation d'une classe, le concepteur peut vouloir représenter ses éléments internes participant et leurs relations pour s'assurer que l'implémenteur implémente en conséquence les collaborations intervenant à l'intérieur de cette classe.

Dans le langage UML 2.0, les classes sont définies en tant que ../glossary.htm#structured_class -- This hyperlink in not present in this generated websiteclasses structurées , pouvant disposer d'une structure interne et de ports. Les classes peuvent donc être décomposées en collections d'éléments connectés qui pourront à leur tour être décomposées plus avant. Une classe peut être encapsulée, en forçant les communications venant de l'extérieur à passer par des ports respectant les interfaces déclarées.

En présence d'une classe et d'une structure complexes, crée un diagramme de structure composite pour cette classe. Modélisez les éléments qui rempliront les rôles afférents au comportement de la classe. Déterminez comment les parties sont 'raccordées' par le biais de connecteurs. Faites usage de ports avec interfaces déclarées si vous voulez permettre à des clients différents un accès à des portions spécifiques du comportement offert par cette classe. Utilisez également des ports afin d'isoler complètement de son environnement les parties internes de cette classe.

Pour plus d'informations sur ce sujet et pour des exemples de diagramme de structure composite, voir Concepts : Classe structurée.

Définition des généralisations Haut de la page

Les classes peuvent être organisées sous une hiérarchie de généralisations de sorte à refléter les comportements communs et la structure commune. Une superclasse commune peut être définie, dont des sous-classes hériteront à la fois le comportement et la structure. La généralisation est une convenance de notation vous permettant de définir à un endroit une structure et un comportement communs, et de la réutiliser là où ce comportement et cette structure se reproduisent. Pour plus d'informations sur les relations de généralisation, reportez-vous à la rubrique Principes et conseils : Généralisation .

Lorsque vous identifiez une généralisation, définissez une superclasse commune qui contiendra les attributs, associations, agrégations et opérations communs. Détachez le comportement commun des classes destinées à devenir des sous-classes de la superclasse commune. Définissez une relation de généralisation de la sous-classe envers la superclasse.

Résolution des collisions entre cas d'utilisation Haut de la page

L'objectif de cette étape est d'éviter des conflits d'accès concurrent pouvant émerger lorsque deux cas d'utilisation, ou plus, sont susceptibles d'accéder simultanément et de manière contradictoire à des instances de la classe de conception.

L'une des difficultés à progresser dans le processus de conception pas à pas, un cas d'utilisation après l'autre, provient du fait que deux cas d'utilisation (ou plus) pourraient tenter d'appeler simultanément et de manière contradictoire des opérations sur des objets de la conception. Dans de tels cas, les conflits d'accès concurrent doivent être identifiés et résolus explicitement.

Si un échange de messages synchrone est utilisé, l'exécution d'une opération bloquera les appels ultérieurs aux objets jusqu'à ce que l'opération se termine. L'échange de messages synchrone implique un traitement des messages selon le principe premier arrivé, premier servi. Ceci peut résoudre un conflit d'accès concurrent, notamment dans les cas où tous les messages ont la même priorité ou dans les cas où chaque message s'exécute dans le même fil d'exécution. Dans les cas où plusieurs fils d'exécution (représentés par des classes actives) sont susceptibles d'accéder à un même objet, des mécanismes explicites doivent être utilisés pour empêcher ou pour résoudre le conflit d'accès concurrent.

Il se peut que des opérations différentes sur le même objet soient appelées simultanément par divers fils d'exécution sans pour autant provoquer un conflit d'accès concurrent ; ainsi, le nom et l'adresse d'un client pourraient être modifiés simultanément sans générer de conflit. Un conflit ne surgit que lorsque deux fils d'exécution différents tentent de modifier la même propriété de l'objet.

Pour chaque objet auquel des fils d'exécution différents pourraient avoir un accès concurrent, identifiez les sections du code devant être protégés contre un accès simultané. Au début de la phase d'élaboration, l'identification de segments de code spécifiques ne sera pas possible ; il suffit à ce stade de détecter les opérations à protéger. Sélectionnez (ou concevez) ensuite des mécanismes de contrôle d'accès adéquats pour empêcher des accès simultanés conflictuels. Parmi ces mécanismes, vous pouvez envisager d'inclure une mise en file d'attente des messages afin de sérialiser les accès, d'utiliser des sémaphores ou des jetons afin de n'autoriser l'accès qu'à un seul fil à la fois, ou encore envisager d'autres variantes de mécanismes de verrouillage. Le choix du mécanisme est conditionné dans une large mesure par l'implémentation et varie habituellement avec le langage de programmation et l'environnement d'exploitation.

Traitement des exigences non fonctionnelles générales Haut de la page

Les classes de conception sont affinées afin de se prêter aux exigences générales, non fonctionnelles. Un apport important dans cette étape provient des exigences non fonctionnelles sur une classe d'analyse qui peuvent déjà avoir été stipulées dans ses exigences spéciales et responsabilités. Ce type d'exigences est souvent spécifié sous l'angle des mécanismes d'architecture (analyse) requis pour réaliser la classe. Au cours de cette étape, la classe est ensuite optimisée en intégrant les mécanismes de conception correspondant à ces mécanismes d'analyse.

Les mécanismes de conception disponibles sont identifiés et caractérisés par l'architecte logiciel . Pour chaque mécanisme de conception requis, qualifiez autant de caractéristiques que possible, en spécifiant des plages de valeurs le cas échéant. Pour plus d'informations sur ces mécanismes, reportez-vous aux rubriques Activité : Identification des mécanismes de conception, Concepts : Mécanismes d'analyse, et Concepts : Mécanismes de conception et d'implémentation.

Divers principes et mécanismes généraux de conception peuvent devoir être pris en compte pour la conception des classes, par exemple en ce qui concerne :

  • l'utilisation de produits et composants existants ;
  • l'adaptation au langage de programmation ;
  • la distribution des objets ;
  • l'atteinte de performances acceptables ;
  • l'atteinte de certains niveaux de sécurité ;
  • le traitement des erreurs ;
  • etc.

Evaluation de vos résultatsHaut de la page

Vérifiez à ce stade le modèle de conception pour confirmer que vos efforts sont orientés dans la bonne direction. Il est inutile d'examiner le modèle dans le détail, mais prêtez toutefois attention aux points de contrôle suivants :



RUP (Rational Unified Process)   2003.06.15