IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langages de programmation Discussion :

Dans quels cas écrire des classes non héritables ?


Sujet :

Langages de programmation

  1. #1
    Membre averti
    Profil pro
    Développeur informatique
    Inscrit en
    Janvier 2003
    Messages
    302
    Détails du profil
    Informations personnelles :
    Localisation : Algérie

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Distribution

    Informations forums :
    Inscription : Janvier 2003
    Messages : 302
    Points : 316
    Points
    316
    Par défaut Dans quels cas écrire des classes non héritables ?
    Salut !

    J'ai vu qu'en C# on pouvait écrire des extensions pour des classes qui ne seraient pas héritables/dérivables, ce qui m'a fait réfléchir à la question : mais pourquoi est-ce que je décidrais que ma classe personne ne devra en hériter ?

  2. #2
    Membre émérite
    Inscrit en
    Janvier 2011
    Messages
    805
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Janvier 2011
    Messages : 805
    Points : 2 918
    Points
    2 918
    Par défaut
    Hello,

    Le danger avec l'héritage (et surtout la surcharge) c'est d'altérer une propriété implicite de la classe mère et d'aboutir à des bugs.

    Un exemple bien connu d'héritage défectueux est de faire dériver une classe Carré d'une classe Rectangle. Si le setter de Carre.Hauteur est redéfini dans la classe Carré pour systématiquement fixer la Largeur à la même valeur (puisqu'un carré doit toujours avoir les côtés de même longueur), on a une propriété du Rectangle qui est violée, à savoir :

    Un consommateur de Rectangle s'attend à ce que

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    r.Largeur = y;
    r.Hauteur = x;
    r.Surface // doit toujours retourner x*y
    Cette propriété n'est plus respectée si on passe à ce consommateur de Rectangle un Carré tel que défini précédemment puisque la surface vaudra dans les faits x*x et non plus x*y.

    Bien sûr c'est un exemple basique mais il est d'autant plus valable pour des bases de code plus complexes. Donc pour éviter la tentation qu'aurait un autre développeur d'hériter de notre classe et de surcharger son comportement, en craignant qu'il puisse mal la surcharger, on scelle la classe. On voit ça parfois dans des bibliothèques ou frameworks.

    Une classe scellée peut aussi être plus performante. Cf https://docs.microsoft.com/en-us/dot...elines/sealing

  3. #3
    Membre chevronné

    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Février 2004
    Messages
    758
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information

    Informations forums :
    Inscription : Février 2004
    Messages : 758
    Points : 2 084
    Points
    2 084
    Par défaut
    J'ai toujours été totalement contre cette mode du private et du sealing de classes en POO, car pour moi cela va à l'encontre d'un des 3 piliers de la POO : la réutilisabilité.

    Et on en manque tellement en développement de réutilisabilité. Mais ca redevient à la mode avec des frameworks de type composants.

  4. #4
    Membre émérite
    Inscrit en
    Janvier 2011
    Messages
    805
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Janvier 2011
    Messages : 805
    Points : 2 918
    Points
    2 918
    Par défaut
    En quoi sceller une classe empêche de la réutiliser ?

  5. #5
    Membre chevronné

    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Février 2004
    Messages
    758
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information

    Informations forums :
    Inscription : Février 2004
    Messages : 758
    Points : 2 084
    Points
    2 084
    Par défaut
    Citation Envoyé par Luckyluke34 Voir le message
    En quoi sceller une classe empêche de la réutiliser ?
    Tu ne peux pas modifier son comportement, ce qui limite quand même fortement sa réutilisation. La capacité à hériter est une grande partie de la réutilisation des classes.

    Le concepteur d'une classe ne sait pas tout ce que d'autres voudront faire avec sa classe, d'où l'intérêt pour moi de laisser ouvert au maximum en POO.

    Rien de plus frustrant d'être bloqué, comme il y a quelques années en DotNet, sur une classe de Microsoft complètement Sealed et en plus de ne pas en avoir le code source.

  6. #6
    Membre émérite
    Inscrit en
    Janvier 2011
    Messages
    805
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Janvier 2011
    Messages : 805
    Points : 2 918
    Points
    2 918
    Par défaut
    Comme je le disais, c'est compréhensible de vouloir empêcher qu'on hérite de sa classe si on craint que les gens ne surchargent en violant des préconditions et invariants.

    Et il vaut souvent mieux utiliser la composition que l'héritage pour réutiliser de l'existant. L'idée, c'est que plutôt que de bidouiller un truc qui existe via l'héritage, on va s'en servir tel quel et adapter le résultat qu'il nous retourne.

  7. #7
    Membre chevronné

    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Février 2004
    Messages
    758
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information

    Informations forums :
    Inscription : Février 2004
    Messages : 758
    Points : 2 084
    Points
    2 084
    Par défaut
    Citation Envoyé par Luckyluke34 Voir le message
    Comme je le disais, c'est compréhensible de vouloir empêcher qu'on hérite de sa classe si on craint que les gens ne surchargent en violant des préconditions et invariants.

    Et il vaut souvent mieux utiliser la composition que l'héritage pour réutiliser de l'existant. L'idée, c'est que plutôt que de bidouiller un truc qui existe via l'héritage, on va s'en servir tel quel et adapter le résultat qu'il nous retourne.
    C'est une manière de faire, qui peut fonctionner dans certains cas, mais clairement pas une solution générale. En composition par interface, tu dois non-seulement avoir les interfaces qui correspondent à ce que tu veux changer (ce qui est aussi très rarement le cas, d'autant plus quand tu n'as pas forcément accès au code source), mais en plus, tu dois très souvent réécrire des méthodes que tu ne voulais pas réécrire : et c'est bien là tout l'intérêt de l'héritage de ne pas avoir à le faire.

    Du moment qu'on a accès au code source, les Private et autres Sealed (C# ici), de mon point de vue, devrait être bannis. Si le code est bien documenté (et donc le contrat de fonctionnement et d'utilisation clair), aucune raison de bloquer quelque chose sous prétexte que "peut-être" ce sera mal utilisé. Mais c'est juste mon avis.

  8. #8
    Expert éminent sénior
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    6 803
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Décembre 2007
    Messages : 6 803
    Points : 32 058
    Points
    32 058
    Par défaut
    Ben, franchement, sur des algos sensibles(pas dans le sens de difficile, dans le sens de sensible métier), genre le calcul des arrondis en comptabilité bancaire, il me semble au contraire nécessaire de rendre tout ça le plus inaccessible possible au commun du programmeur bancaire. Mais c'est une décision fonctionnelle, pas technique.
    Les 4 règles d'airain du développement informatique sont, d'après Michael C. Kasten :
    1)on ne peut pas établir un chiffrage tant qu'on a pas finalisé la conception
    2)on ne peut pas finaliser la conception tant qu'on a pas complètement compris toutes les exigences
    3)le temps de comprendre toutes les exigences, le projet est terminé
    4)le temps de terminer le projet, les exigences ont changé
    Et le serment de non-allégiance :
    Je promets de n’exclure aucune idée sur la base de sa source mais de donner toute la considération nécessaire aux idées de toutes les écoles ou lignes de pensées afin de trouver celle qui est la mieux adaptée à une situation donnée.

  9. #9
    Membre émérite
    Inscrit en
    Janvier 2011
    Messages
    805
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Janvier 2011
    Messages : 805
    Points : 2 918
    Points
    2 918
    Par défaut
    En fait on est en train de parler dans le vide, ça dépend entièrement du but recherché :

    • Etendre un comportement d'un framework à un point d'accroche prévu par ses concepteurs : ils doivent fournir une classe mère non sealed ou plus commodément une classe abstraite ou une interface à implémenter.

    • Etendre un comportement d'un framework à un endroit pas prévu par ses concepteurs : attention à la faisabilité. Il vaut mieux ne pas ouvrir la boîte et passer au point suivant.

    • Utiliser une classe ou une partie d'une bibliothèque fournie : son fournisseur est quand même le mieux placé pour savoir comment bien l'utiliser et c'est tout à fait légitime qu'il guide les consommateurs de manière contraignante. On compose (relation de type "avoir") cette classe pour l'utiliser telle quelle. Si on veut rendre le comportement polymorphique et que la classe n'a pas d'interface, on peut la wrapper dans une classe à nous qui a une interface (ça permet aussi de n'exposer que les opérations de la classe tierce dont tu as réellement besoin).

    • Détourer un petit bout de logique d'une classe tierce pour le greffer dans notre code : il faut évidemment le code source parce que là on veut "ouvrir la boîte" fournie et piquer une "pièce du moteur". Dans ce cas-là, sealed ne gêne pas.

    • Amender un comportement buggé d'une bibliothèque tierce : le bug report est encore la meilleure solution. Si on a le code source et du temps, on peut fixer le bug et à ce moment-là autant envoyer une pull request dessus. Hériter et surcharger en se substituant aux auteurs de la bibliothèque peut marcher sur des choses très simples, mais ça devient très risqué sur du complexe : c'est consommateur de temps pour vérifier les effets de bord, sujet à fragilité lors de la mise à jour de version, etc.

  10. #10
    Membre chevronné

    Profil pro
    Conseil - Consultant en systèmes d'information
    Inscrit en
    Février 2004
    Messages
    758
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Conseil - Consultant en systèmes d'information

    Informations forums :
    Inscription : Février 2004
    Messages : 758
    Points : 2 084
    Points
    2 084
    Par défaut
    Citation Envoyé par Luckyluke34 Voir le message
    Utiliser une classe ou une partie d'une bibliothèque fournie : son fournisseur est quand même le mieux placé pour savoir comment bien l'utiliser et c'est tout à fait légitime qu'il guide les consommateurs de manière contraignante. On compose (relation de type "avoir") cette classe pour l'utiliser telle quelle. Si on veut rendre le comportement polymorphique et que la classe n'a pas d'interface, on peut la wrapper dans une classe à nous qui a une interface (ça permet aussi de n'exposer que les opérations de la classe tierce dont tu as réellement besoin).
    Très beau résumé Luckyluke Je suis tout à fait d'accord avec tout, sauf avec ce point.

    Un notion de contrat ne devrait pas être contraignant au niveau de son code : du moment que le contrat d'utilisation est clair (documentation, code source disponible, interfaces et/ou abstractions déjà présentes), un développeur saura l'utiliser de la manière envisagée par son créateur initial, il a toute les cartes en main pour ça.

    Mais de là à forcer cette limitation par le développeur initial, alors qu'il est strictement impossible de connaître tous les cas d'utilisation futurs, j'ai toujours trouvé ça très dommage. Charge à celui qui veut utiliser les briques d'une autre manière, sachant pertinemment comment il devrait normalement les utiliser, de supporter les conséquences de ses besoins.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. UML : Qui s'en sert ? Pourquoi ? Dans quels cas ? Où ?
    Par Matthieu Brucher dans le forum UML
    Réponses: 83
    Dernier message: 10/06/2013, 16h13
  2. Réponses: 7
    Dernier message: 26/09/2012, 19h44
  3. Dans quels cas est-on obligés d'utiliser des mutex ?
    Par kidpaddle2 dans le forum Threads & Processus
    Réponses: 3
    Dernier message: 18/07/2010, 20h05
  4. [Zope] Dans quel cas utiliser zope ?
    Par kalimero dans le forum Zope
    Réponses: 3
    Dernier message: 26/07/2005, 09h08
  5. [corba] débutant : dans quels cas l'utiliser
    Par jmturc dans le forum CORBA
    Réponses: 2
    Dernier message: 10/10/2002, 08h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo