9
votes

Objet de finale et scellée

Pourquoi quelqu'un voudrait-il marquer une classe comme finale ou scellée?


7 commentaires

Un titre n'est pas une question vraiment.


Parce que la classe ne veut pas avoir d'enfants et que nous devrions respecter ses souhaits. :)


@klabranche: Faites-moi savoir quand ils le changent à un stérilisé ou Nathered classe.


"Un titre n'est pas une question vraiment" Humbug. Vous devez avoir négligé la marque d'interrogation, qui était le dernier caractère du sujet.


Re: "Parce que la classe ne veut pas avoir d'enfants et nous devrions respecter ses souhaits" - L'auteur de la classe d'origine n'aurait pas dû dire à cela.


"L'auteur de la classe d'origine n'aurait pas dû dire à ce sujet" Il devrait, parce que si vous héritez de sa classe, il change des détails de la mise en œuvre et il casse votre code - devine qui vous allez blâmer? Je veux marquer la classe scellée lorsque je veux modifier une implémentation, cela ne casse pas l'utilisation, mais peut casser l'héritage.


"Un titre n'est pas une question vraiment." - Spender. 6 Les votes disent que vous avez tort.


3 Réponses :


10
votes

Parce que la création d'un type d'héritage est beaucoup plus difficile que la plupart des gens ne le pensent. Il est préférable de marquer tous les types de cette manière par défaut, car cela empêchera les autres de hériter d'un type qui n'a jamais été étendu.

Si un type doit être prolongé est une décision du développeur qui l'a créé, non pas le développeur qui se présente plus tard et veut l'étendre.


5 commentaires

Intéressant que cela a été évité - j'aimerais entendre un contre-argument à ce que j'ai écrit ici.


Je suis avec le Downvoter à ce sujet, mais ne le considère pas une situation de -1 :) Travailler avec un code 3ème partie qui a été serré de manière restrictive peut rendre la vie misérable, surtout lorsque des bugs doivent être résolus. Plus d'une fois, j'ai dû envelopper des cours de buggy car les niveaux de protection étaient inutilement restrictifs.


La prestation de performance est le seul avantage qui me semble raisonnable.


Pourquoi ne devrais-je pas, le développeur utilisant une classe, décider si je devrais le sous-classer ou non? Si cela n'est pas conçu pour l'héritage, je peux en tenir compte.


"Pourquoi ne devrais-je pas, le développeur utilisant une classe, décider" pour la même raison pour laquelle vous ne devez pas décider si vous accédez à un membre privé ou non. Parce que le développeur qui a conçu la classe a décidé qu'il serait plus sûr. Bien sûr, il existe des approches plus strictes et plus douces. Vous ne trouverez pas de mots-clés privés et scellés / finaux dans JavaScript et d'autres langues «douces».



14
votes

Selon Wikipedia , "Les classes scellées sont principalement utilisées pour empêcher dérivation. Ils ajoutent un autre niveau de stricteur pendant la compilation, améliorent l'utilisation de la mémoire et déclencher certaines optimisations qui améliorent l'efficacité du temps d'exécution. "

Aussi, de Blog de Patrick Smacchia :

  • Versioning: Lorsqu'une classe est scellée à l'origine, elle peut changer à l'avenir à l'avenir sans casser la compatibilité. (...)

  • Performances: (...) Si le compilateur JIT voit un appel à une méthode virtuelle à l'aide d'un type scellé, le compilateur JIT peut produire un code plus efficace en appelant la méthode non pratiquement. (...)

  • Sécurité et prévisibilité: une classe doit protéger son propre état et ne pas se permettre de devenir corrompu. Lorsqu'une classe est non scellée, une classe dérivée peut accéder et manipuler l'état de la classe de base si des champs de données ou des méthodes qui manipulent en interne sont accessibles et non privées. (...)

    Ce sont toutes de très bonnes raisons - je n'étais en fait pas au courant des implications de la prestation de la performance jusqu'à ce que je le regarde juste maintenant :)

    Les points de version et de sécurité semblent un avantage énorme en termes de confiance du code, qui est très bien justifiée sur tout type de grand projet. Ce n'est pas une chute pour les tests unitaires, bien sûr, mais cela aiderait.


4 commentaires

FWIW: Je suis à peu près sûr que le point chaud ne bénéficie pas de beaucoup de prestations de performance, car elle prend en charge la dépostimation dynamique. Fondamentalement, il suppose que toutes les méthodes ne sont pas virtuelles jusqu'à ce qu'elle charge réellement une autre version de la méthode. Lorsque cela se produit, il remonte et "dépostimise" tous les endroits où il a fait un appel non virtuel pour faire un appel virtuel.


Versioning? Je ne suis pas ça. Cela ressemble simplement à votre dicton "Vous pouvez supprimer la propriété" scellée "de la classe et recompiler" -C'est-ce que vous ne parlez pas pourquoi vous le feriez en premier lieu. Performance? Intéressant! Sécurité? Les sous-classes ne peuvent accéder que ce que la classe de base permet. Si la classe de base souhaite "protéger" ses données, il ne devrait pas utiliser les propriétés "protégées". Ce n'est pas une raison pour sceller la classe entière. Je manque ça.


Je pense que la version suivante s'appliquerait si vous avez publié une classe «bêta», peut-être en interne au sein de votre entreprise. Forcer à être scellé jusqu'à ce que cette classe atteigne le statut de «version». Sécurité? Classe de base publique avec membre protégé, une classe dérivée scellée peut accéder au membre, mais personne d'autre ne peut dériver de cette classe Classe et gâchis avec le membre.


Versioning consiste à changer la classe de base et à ne pas casser toutes les sous-classes.



6
votes

Joshua Bloch dans son livre Efficace Java en parle. Il dit "document pour l'héritage ou interdire". Le point est que la classe est une sorte de contrat entre l'auteur et le client. Autoriser le client d'hériter de la classe de base rend ce contrat beaucoup plus strict. Si vous allez hériter de cela, vous allez probablement remplacer certaines méthodes, sinon vous pouvez remplacer l'héritage avec la composition. Quelles méthodes sont autorisées à être remplacées et que vous devez les mettre en œuvre - doit être documentée ou votre code peut conduire à des résultats imprévisibles. Autant que je me souvienne, il montre un tel exemple - voici une classe de collection avec des méthodes xxx

Il existe une certaine implémentation, c'est-à-dire arraylist. Vous voulez maintenant hériter de lui et remplacer certaines méthodes, il est donc imprimé pour consoler un message lorsque l'élément est ajouté. Maintenant, avez-vous besoin de remplacer les deux ajouter et addall , ou uniquement ajouter ? Cela dépend de la manière dont Addall est implémentée - fonctionne-t-il directement avec l'état interne directement (comme l'arraylist le fait) ou des appels Ajouter (comme abstractcollection). Ou peut-être qu'il est addInternal , appelé à la fois par ajouter et addall . Il n'y avait pas de telles questions tant que vous n'avez pas décidé d'hériter de cette classe. Si vous l'utilisez simplement - cela ne vous dérange pas. L'auteur de la classe doit donc le documenter s'il veut que vous héritez de sa classe.

Et s'il veut changer la mise en œuvre à l'avenir? Si sa classe n'est utilisée que, jamais héritée de, rien ne l'empêche d'évoluer la mise en œuvre plus efficace. Maintenant, si vous avez hérité de cette classe, examiné la source et trouva que Addall Appels Ajouter , vous ne remplacez que Ajouter . L'auteur ultérieur change de mise en œuvre SO Addall N'appelez plus Ajouter - Votre programme est cassé, le message n'est pas imprimé lorsque Addall est appelé. Ou vous avez regardé la source et avez trouvé que Addall n'appelle pas ADD Add Ajouter, alors vous remplacez Ajouter et addall . Maintenant, l'auteur change de mise en œuvre, donc addall appels Ajouter - Votre programme est brisé à nouveau, lorsque addall est appelé message est imprimé deux fois pour chaque élément. < / p>

Donc - si vous voulez que votre classe soit héritée, vous devez documenter comment. Si vous pensez que vous devriez peut-être modifier quelque chose à l'avenir qui peut enfreindre des sous-classes - vous devez penser à l'éviter. En laissant vos clients hériter de votre classe, vous exposez beaucoup plus de détails de mise en œuvre internes que vous faites lorsque vous les laissez simplement utiliser votre classe - vous exposez le flux de travail interne, qui est souvent soumis à des modifications des futures versions.

Si vous exposez certains détails et les clients comptent sur eux - vous ne pouvez plus les changer. Si cela vous convient, ou si vous avez documenté ce que vous pouvez et ce qui ne peut pas être remplacé - c'est bien. Parfois, vous ne le voulez pas. Parfois, vous voulez simplement dire - «Utilisez simplement cette classe, n'héritez jamais, car je souhaite une liberté de modifier les détails de la mise en œuvre internes».

aussi fondamentalement commenter »car la classe ne veut pas avoir Tous les enfants et nous devrions respecter ses souhaits "est correct.

Alors, quelqu'un veut marquer une classe comme finale / scellée, lorsqu'il pense que les modifications éventuelles de la mise en œuvre sont plus utiles que l'héritage. Il existe d'autres moyens d'atteindre des résultats similaires à l'héritage.


0 commentaires