Chapitre 8 Les classes abstraites L'héritage multiple Difficultés inhérentes à l'héritage Classe abstraite (ou virtuelle) ● ● ● ● ● Une classe est dite abstraite si elle encapsule au moins une méthode abstraite (ou virtuelle) Une méthode est dite abstraite si elle n'est pas implémentée Une méthode abstraite est définie uniquement par sa signature : liste de paramètres et type du retour Une classe abstraite étant incomplète, elle ne peut avoir d'instance Une classe abstraite n'ayant que des méthodes abstraites est appelée interface (ou classe virtuelle pure) Classe concrète ● ● ● Il appartient aux classes dérivées d'une classe abstraite de définir du code pour chacune de ses méthodes abstraites : on parle alors de classe concrète Les classes concrètes sont les seules à même d'être instanciées En notation UML les noms des classes concrètes sont en caractère droit et les noms des classes abstraites sont en italique But des classes abstraites ● ● ● Définir un cadre de travail pour les classes dérivées Proposer un ensemble de méthodes que l'on retrouvera tout au long de la chaîne de classe Ce mécanisme est fondamental pour la mise en place du polymorphisme : faculté présenté par certaines méthodes de signature identique dont le comportement est différent selon l'objet auquel elles s'appliquent Choix entre classe abstraite ou concrète ? ● ● La classe « être vivant » ne peut pas avoir d'instance : elle ne correspond à aucun objet concret mais plutôt au concept d'un objet capable de « se déplacer », « respirer », « se nourrir »... Dépend souvent du cahier des charges du logiciel : – – les classes concrètes sont celles qui possèdent des instances Par généralisation on trouve les classes abstraites qui permettront de bénéficier du polymorphisme Les classes abstraites en python ● ● Pas de mécanismes spéciaux pour définir des méthodes abstraites, donc a fortiori pas de mécanisme de définition d'interfaces Solution utilisée : – – Une méthode abstraite est une méthode dont le corps est réduit à la levée d'une exception pour non implémentation : « raise NotImplementedError » Les méthodes dérivées sont ainsi forcées de récrire toutes les méthodes abstraites d'une classe abstraite pour qu'elle soit utilisable Solution alternative ● ● Le typage dynamique permet d'utiliser le polymorphisme sans exploiter nécessairement l'héritage : le duck typing « If it looks like a duck and quacks likes a duck, it must be a duck » : il suffit qu'un objet implémente les méthodes nécessaires à la réalisation d'une tâche (c.a.d. une interface) pour pouvoir les appeler ; il n'a pas besoin de dériver d'une classe de base qui matérialise cette interface Problèmes généraux de l'héritage ● Hiérarchies trop lourdes Dérivations à tour de bras (ChiensNoirs et ChienBlancs) – Trop de classes intermédiaires (classe abstraite dérivée une seule fois) L'héritage de construction : ajouter des attributs qui modifient totalement le concept (faire « rectangle » à partir de « ligne ») – ● ● Les incohérences conceptuelles : Oiseau qui possède la méthode « voler » utilisé pour construire la classe des Pingouins... qui sont bien des oiseaux mais qui ne volent pas ! (il existe dans certains langage des mécanismes d'héritage sélectif : nuit totalement au polymorphisme) L'héritage multiple ● Extension au modèle d'héritage simple : on autorise une classe à posséder plusieurs classes mères afin de modéliser une généralisation multiple Mammifère Herbivore Vache Problèmes de l'héritage multiple ● ● ● Attributs ou méthodes des classes mères de même nom : parfois préfixage de la propriété par le nom de sa classe d'origine Héritage à répétition : des classes dérivent d'une même classe puis servent ensemble de classes mères pour une nouvelle classe ! Certains langages bannissent l'héritage multiple (pas python) et proposent l'alternative intéressante : les interfaces Le cas des interfaces ● ● ● ● Les problèmes de l'héritage multiple le rend peu utilisé D'autres mécanismes sont apparus tels que les interfaces Une interface est une classe sans attributs (mais pouvant contenir des constantes) et dont toutes les méthodes sont abstraites En plus de ses caractéristiques d'héritage une classe peut implémenter une interface si elle propose une implémentation pour toutes les méthodes de l'interface Intérêt des interfaces ● ● ● Création de relations entre différentes classes sans liens de parenté mais implémentant les mêmes interfaces Les méthodes décrites dans les interfaces sont polymorphes car implémentées différemment dans chaque classe implémentant une même interface Chaque classe peut implémenter un nombre quelconque d'interface Interfaces en python ● ● ● Aucun mécanismes prévus pour l'instant L'aspect dynamique du typage rend moins intéressant l'utilisation des classes abstraites et donc des interfaces Une simulation simpliste est de définir une classe mère sans constructeurs ni attributs et un ensemble de signatures de méthodes dont les corps ne font que lever une exception de type « NotImplementedError »