Instructions: Généralisation
La généralisation est une relation de classe qui enregistre les propriétés communes à différentes classes. Ces instructions expliquent comment utiliser cette relation.
Relations
Description principale

Généralisation

Dans la vraie vie, beaucoup de choses ont des propriétés en commun. Un chien et un chat sont, par exemple, tous deux des animaux. Les propriétés peuvent aussi avoir des propriétés en commun ; vous pouvez les clarifier en utilisant une généralisation entre leurs classes. En plaçant les propriétés communes dans des classes à part entière, vous pourrez changer et entretenir votre système plus facilement dans le futur.

Une généralisation montre qu'une classe hérite d'une autre. La classe qui hérite est appelée un enfant. La classe dont elle hérite est appelée un parent. L'héritage signifie que la définition du parent - incluant les propriétés comme les attributs, les relations ou les opérations sur ses objets - est aussi valide pour les objets de l'enfant. La généralisation est établie de la classe enfant vers la classe parent.

La généralisation peut avoir lieu en plusieurs étapes, ce qui vous permet de modéliser des hiérarchies d'héritage à plusieurs niveaux. Les propriétés générales sont placées dans la partie supérieure de la hiérarchie d'héritage et les propriétés spécifiques dans la partie inférieure. En d'autres mots, vous pouvez utiliser la généralisation pour modéliser les spécialisations d'un concept plus général.

Exemple

Dans le système d'une machine de recyclage, toutes les classes - canette, bouteille et caisse - décrivent différents types d'articles consignés. Ils ont deux propriétés en commun, en dehors du fait d'être du même type : chacun a une taille et un poids. Vous pouvez modéliser ces propriétés en utilisant des attributs et des opérations dans une classe séparée article consigné. Les canettes, les bouteilles et les caisses hériteront des propriétés de cette classe.

Diagramme décrit dans le texte d'accompagnement.

Les classes canette, bouteille et caisse ont les propriétés taille et poids en commun. Chacune est une spécialisation du concept général article consigné.

Héritage multiple

Une classe peut hériter de plusieurs autres classes grâce à l'héritage multiple, bien que généralement elle n'hérite que d'une.

Si vous utilisez les héritages multiples, voici quelques problèmes potentiels que vous devez connaître :

  • Si la classe hérite de plusieurs classes, vous devez vérifier comment les relations, les opérations et les attributs sont nommés chez les parents. Si le même nom apparaît chez plusieurs acteurs, vous devez décrire ce que cela signifie à la classe qui hérite, par exemple en qualifiant le nom pour indiquer sa source de déclaration.
  • Avec l'héritage répété, un enfant hérite plusieurs fois d'un parent. Lorsque cela arrive, la hiérarchie d'héritage aura une forme de losange, comme illustré ci-dessous.

Diagramme décrit dans le texte d'accompagnement.

Héritage multiple et répété. La classe Fenêtre défilante avec boîte de dialogue a hérité de la classe fenêtre plusieurs fois.

Une question pouvant être soulevée dans ce contexte est "Combien de copies des attributs de la Fenêtre sont incluses dans les instances de la Fenêtre défilante avec boîte de dialogue ?". Si vous utilisez l'héritage répété, vous devez donc avoir une définition claire de sa sémantique ; dans la plupart des cas, cela est défini par le langage de programmation prenant en charge l'héritage multiple.

Généralement, les règles du langage de programmation gérant les héritages multiples sont complexes et souvent difficile à utiliser correctement. Utilisez donc les héritages multiples seulement lorsque c'est nécessaire et toujours avec prudence.

Classes abstraites et classes concrètes

Une classe qui n'est pas instanciée et qui n'existe que dans le but que les autres classes héritent d'elles est une classe abstraite. Une classe instanciée est une classe concrète. Remarquez qu'une classe abstraite doit avoir au moins un enfant pour être utile.

Exemple

Un emplacement de palette dans le système de gestion de dépôt est une classe entité abstraite qui représente les propriétés communes aux différents types d'emplacements de palettes. Les classes concrètes poste, transporteur et unité de stockage, qui peuvent toutes être des emplacements de palette dans le dépôt, héritent de cette classe. Tous ces objets ont une propriété en commun : ils peuvent tous contenir une ou plusieurs palettes.

Diagramme décrit dans le texte d'accompagnement.

La classe héritée, ici l'emplacement de la palette, est abstraite et n'est pas instanciée seule.

Utilisation

Les stéréotypes de classes ayant des buts différents, l'héritage entre stéréotypes de classe n'a aucun sens. Faire hériter une classe frontière d'une classe entité, par exemple, ferait de la classe frontière une sorte d'hybride. Il faut donc utiliser les généralisations uniquement entre les classes du même stéréotype.

Vous pouvez utiliser la généralisation pour exprimer deux relations entre des classes :

  • Le sous-typage, qui définit que l'enfant est le sous-type du parent. Le sous-typage signifie que l'enfant hérite de la structure et du comportement du parent et que l'enfant est du même type que le parent (cela signifie que l'enfant est un sous-type qui peut remplacer tous ses parents dans toutes les situations).
  • Le sous-classement, qui définit que l'enfant est une sous-classe (mais pas un sous-type) du parent. Le sous-classement signifie que l'enfant hérite de la structure et du comportement du parent et qu'il n'est pas du même type que le parent.

Vous pouvez créer ce genre de relations en séparant les propriétés communes à plusieurs classes et en les plaçant dans des classes séparées dont les autres héritent. Vous pouvez aussi créer de nouvelles classes gérant les plus généraux en les laissant hériter des classes générales.

Si les deux variantes coïncident, vous n'aurez aucune difficulté à configurer le bon héritage entre les classes. Parfois, cependant, les variantes ne coïncident pas, dans ce cas vous devez faire attention à ce que l'utilisation de l'héritage reste compréhensible. Vous devez au moins connaître le but de chaque relation d'héritage présente dans le modèle.

Utilisation de l'héritage pour prendre en charge le polymorphisme

Le sous-typage signifie que l'enfant est un sous-type qui peut remplacer tous ses parents dans toutes les situations. Le sous-typage est un cas spécial du polymorphisme. C'est une propriété importante parce qu'elle permet de conceptualiser tous les clients (les objets qui utilisent les parents) sans tenir compte des enfants potentiels des parents. Cela rend les objets du client plus communs et réutilisables. Lorsque le client utilisera l'objet réel, il fonctionnera toujours de la même façon et l'objet effectuera toujours sa tâche. Le sous-typage assure que le système tolérera les changements dans l'ensemble des sous-types.

Exemple

Dans un système de gestion de dépôt, la classe Interface transporteur définit les fonctionnalités de base pour la communication avec tous les types d'équipement de transport comme les grues et les camions. La classe définit, entre autres choses, l'opération Exécuter le transport.

Diagramme décrit dans le texte d'accompagnement.

Les interfaces des classes Camion et Grue héritent de l'interface transporteur. Cela signifie que les objets des deux classes répondront au message Exécuter le transport. Les objets peuvent remplacer l'interface Transporteur à n'importe quel moment et exécuteront son comportement. Les autres objets (les objets client) peuvent donc envoyer un message à un objet de l'interface Transporteur, sans savoir si l'interface Camion ou l'interface Grue répondra au message.

La classe interface Transporteur peut même être abstraite, jamais instanciée seule. Dans ce cas, l'interface Transporteur peut seulement définir seulement la signature de l'opération Exécuter le transport tandis que les classes enfant l'implémentent.

Certains langages orientés objet, comme C++, utilisent la hiérarchie de classe comme une hiérarchie de type, obligeant le concepteur à utiliser l'héritage pour effectuer des sous-typages dans le modèle de conception. D'autres langages, comme Smalltalk-80, n'effectuent pas de contrôle de typage pendant le temps de compilation. Si les objets ne peuvent pas répondre à un message reçu, ils généreront un message d'erreur.

Utiliser la généralisation pour indiquer les relations de sous-type, même pour les langages sans contrôle de typage, peut être une bonne idée. Dans certains cas vous devriez utiliser la généralisation pour rendre le modèle d'objet et le code source plus faciles à comprendre et à entretenir, sans tenir compte du fait que le langage l' autorise ou pas. L'intérêt de cette utilisation de l'héritage dépend beaucoup des conventions du langage de programmation.

Utilisation de l'héritage pour prendre en charge la réutilisation de l'implémentation

Le sous-classement est l'aspect "réutilisation" de la généralisation. Lorsque vous définissez des sous-classes, vous choisissez les parties de l'implémentation que vous pouvez réutiliser en héritant de propriétés définies par d'autres classes. Le sous-classement allège la charge de travail et vous permet de réutiliser le code lors de l'implémentation d'une classe spécifique.

Exemple

Dans la bibliothèque de classe de Smalltalk-80, la classe Dictionnaire hérite des propriétés de l'ensemble.

Diagramme décrit dans le texte d'accompagnement.

Cette généralisation permet au dictionnaire de réutiliser certaines méthodes générales et certaines stratégies de stockage de l'implémentation de l'ensemble. Même si un dictionnaire peut être vu comme un ensemble (contenant des paires de valeur clé), ce n'est pas un sous-type de l'ensemble car on ne peut pas ajouter n'importe quelle sorte d'objet à un dictionnaire, mais seulement des paires de valeurs clés. Les objets qui utilisent le dictionnaire ne savent pas que c'est un ensemble.

Le sous-classement crée souvent des hiérarchies d'héritage illogiques, difficiles à comprendre et à entretenir. Il n'est donc pas recommandé d'utiliser l'héritage seulement pour la réutilisation, à moins qu'autre chose ne soit recommandée pour l'utilisation de votre langage de programmation. La maintenance de ce genre de réutilisation est généralement assez délicate. Tout changement dans la classe Ensemble implique des grands changements pour toutes les classes héritant de la classe Ensemble. Gardez cela à l'esprit et n'héritez que des classes stables. L'héritage gèlera l'implémentation de la classe Ensemble parce qu'y apporter des changements est trop coûteux.

Héritage dans les langages de programmation

Le fait d'utiliser des relations de généralisation lors de la conception doit largement dépendre de la sémantique et des utilisations de l'héritage proposées par le langage de programmation. Les langages orientés objet, contrairement aux langages non-orientés objet, prennent en charge l'héritage entre classes. Il vaut mieux gérer les caractéristiques des langages dans le modèle de conception. Si vous utilisez un langage ne prenant pas en charge l'héritage ou l'héritage multiple, vous devez simuler l'héritage dans l'implémentation. Dans ce cas, il vaut mieux modéliser la simulation dans le modèle de conception et ne pas utiliser les généralisations pour décrire les structures d'héritage. Modéliser des structures d'héritage avec les généralisations puis simuler l'héritage dans l'implémentation peut gâcher l'implémentation.

Si vous utilisez un langage ne prenant pas en charge l'héritage ou l'héritage multiple, vous devez simuler l'héritage dans l'implémentation. Dans ce cas, il vaut mieux modéliser la simulation dans le modèle de conception et ne pas utiliser les généralisations pour décrire les structures d'héritage. Modéliser des structures d'héritage avec les généralisations puis simuler l'héritage dans l'implémentation peut gâcher l'implémentation.

Vous devrez probablement changer les interfaces et les autres propriétés d'objet pendant la simulation. Il est recommandé de simuler l'héritage d'une des façons suivantes :

  1. En laissant l'enfant envoyer des messages au parent.
  2. En dupliquant le code du parent chez chaque enfant. Dans ce cas, il n'y a pas de classe parent créée.

Exemple

Dans cet exemple, les enfants réacheminent des messages aux parents via des liens qui sont des instances d'associations.

Diagramme décrit dans le texte d'accompagnement.

Une classe spéciale est attribuée aux comportements communs aux Canettes, aux Bouteilles et aux Caisses. Les objets partageant ce comportement envoient un message à l'objet Article consigné pour exécuter le comportement quand il le faut.