68 votes

Dois-je recommander les cours de scellement par défaut ?

Dans un grand projet pour lequel je travaille, j'envisage de recommander aux autres programmeurs de toujours sceller leurs classes s'ils n'ont pas réfléchi à la manière dont leurs classes doivent être sous-classées. Souvent, les programmeurs moins expérimentés n'y pensent jamais.

Je trouve étrange qu'en Java et en C# les classes soient non scellées / non finales par défaut. Je pense que rendre les classes scellées améliore grandement la lisibilité du code.

Remarquez qu'il s'agit d'un code interne que nous pouvons toujours modifier dans le cas, rare, où nous devons créer une sous-classe.

Quelles sont vos expériences ? Je rencontre une certaine résistance à cette idée. Les gens sont-ils si paresseux qu'ils ne prennent pas la peine de taper sealed ?

27 votes

La sous-classification est rare ? !

12 votes

Comment le scellement d'une classe améliore-t-il sa lisibilité ?

4 votes

Peut-être que j'exagère un peu, mais j'ai dû utiliser le sealed mot-clé sur un cours que j'ai écrit quelques fois dans ma carrière. Donc, non, je ne recommande pas quelque chose comme ça ou Anders Hejlsberg sera en colère contre vous.

65voto

Jon Skeet Points 692016

Ok, comme tant d'autres personnes ont pesé dans la balance...

Oui, je pense qu'il est tout à fait raisonnable de recommander que les classes soient scellées par défaut.

Cela va dans le sens de la recommandation de Josh Bloch dans son excellent livre Java efficace, 2e édition :

Concevoir pour l'héritage, ou l'interdire.

Concevoir pour l'héritage, c'est dur et peut faire votre mise en œuvre moins flexible, surtout si vous avez des méthodes virtuelles, dont l'une appelle l'autre. Ce sont peut-être des surcharges, peut-être pas. Le fait que l'une appelle l'autre doit être documenté Sinon, vous ne pouvez pas surcharger l'une ou l'autre méthode en toute sécurité - vous ne savez pas quand elle sera appelée, ni si vous pouvez appeler l'autre méthode sans risquer un débordement de pile.

Si, par la suite, vous voulez changer quelle méthode appelle quelle autre dans une version ultérieure, vous ne pouvez pas le faire, car vous risqueriez de casser les sous-classes. Donc, au nom de la "flexibilité", vous avez en fait fait l'implémentation moins flexible, et que vous deviez documenter les détails de votre implémentation de manière plus précise. Cela ne me semble pas être une bonne idée.

Ensuite, il y a l'immuabilité - j'aime les types immuables. Je trouve qu'il est plus facile de raisonner sur eux que sur les types mutables. C'est une des raisons pour lesquelles le Joda Time est plus agréable que l'utilisation de l'API Date y Calendar en Java. Mais une classe non scellée ne peut jamais être connu sous le nom de pour être immuable. Si j'accepte un paramètre de type Foo je pourrai peut-être compter sur les propriétés déclaré dans Foo de ne pas être modifié au fil du temps, mais je ne peux pas compter sur le fait que l'objet lui-même ne soit pas modifié - il pourrait y avoir une propriété mutable dans la sous-classe. Que le ciel me vienne en aide si cette propriété est également utilisée par une surcharge d'une méthode virtuelle. Dites adieu à bon nombre des avantages de l'immuabilité. (Ironiquement, Joda Time a de très grandes hiérarchies d'héritage - souvent avec des choses disant "les sous-classes doivent être immuables". La grande hiérarchie d'héritage de Chronology le rendait difficile à comprendre lors du portage en C#).

Enfin, il y a l'aspect de la surutilisation de l'héritage. Personnellement, je préfère la composition à l'héritage lorsque c'est possible. J'adore le polymorphisme pour les interfaces, et le occasionnellement J'utilise l'héritage de l'implémentation - mais c'est rarement un bon ajustement dans mon expérience. Rendre les classes scellées évite qu'elles soient inapproprié dérivé d'où la composition serait mieux adaptée.

EDIT : J'aimerais également indiquer aux lecteurs les sites suivants Article du blog d'Eric Lippert datant de 2004 sur la raison pour laquelle tant de classes du cadre sont scellées. Il y a beaucoup d'endroits où j'aurais aimé que .NET fournisse une fonction interface nous pourrions travailler à la testabilité, mais c'est une demande légèrement différente...

0 votes

Voilà le problème : je suis d'accord avec la citation. Mon problème est le suivant : si vous écrivez du code avec sealed par défaut, vous reconnaissez la possibilité dans le futur qu'il devienne unsealed, ce qui signifierait que vous travaillez à partir d'un modèle plus restreint vers un modèle moins restreint, ce qui peut causer des problèmes. Je dirais que si vous voulez vraiment écrire du code qui est scellé par défaut, vous ne devriez pas écrire ce code dans un langage qui a de l'héritage. Il est peut-être plus approprié d'utiliser un outil qui a un comportement par défaut plus approprié de composition que d'héritage.

1 votes

@Paul : Ce serait certainement bien si C# et Java encourageaient davantage la composition... mais vous pouvez toujours travailler avec eux de manière compositionnelle assez facilement. Et bien que oui, il peut certainement y avoir des inconvénients à passer du scellé au non scellé, au moins c'est faisable - alors qu'une fois que le génie est sorti de la bouteille, vous ne pouvez vraiment pas faire autrement. ne peut pas rendre une classe non scellée scellée de manière compatible avec la source, à moins que vous ne puissiez garantir que personne a dérivés de la classe.

9 votes

Les conseils de Bloch sont généralement pas applicable à la plupart des développeurs. La plupart des gens ne publient pas des API publiques à des millions d'utilisateurs pendant des décennies. Comme OP, ils travaillent en interne, l'économie de l'évolution des API est complètement différente. Les changements incompatibles avec le passé ne sont pas seulement possibles et autorisés, ce sont des activités quotidiennes.

19voto

Jerry Nixon - MSFT Points 12256

Je pense que les décisions de conception architecturale sont prises pour communiquer aux autres développeurs (y compris les futurs développeurs de maintenance) quelque chose d'important.

Le scellement des classes indique que l'implémentation ne doit pas être surchargée. Elle indique que la classe ne doit pas être usurpée. Il y a de bonnes raisons de sceller.

Si vous adoptez l'approche inhabituelle consistant à tout sceller (et c'est inhabituel), vos décisions de conception communiquent alors des choses qui ne sont pas vraiment importantes, comme le fait que la classe n'a pas été prévu pour être hérité par le développeur original/auteur.

Mais alors comment communiquer aux autres développeurs que la classe devrait ne peut être hérité à cause de quelque chose ? Tu ne peux vraiment pas. Vous êtes coincé.

De plus, sceller une classe n'améliore pas la lisibilité. Je ne le vois pas. Si l'héritage est un problème dans le développement de la POO, alors nous avons un problème beaucoup plus grand.

17 votes

Si une classe est scellée, le code qui l'utilise est plus lisible car vous n'avez pas à tenir compte de la variance de la sémantique. Vous savez plus simplement comment elle se comportera.

4 votes

@JonSkeet : Je dirais que l'amélioration de la lisibilité vient vraiment de l'assurance implicite que la sémantique ne changera pas ; dans la situation posée par le PO, cependant, l'utilisation par défaut de sealed défait complètement cette assurance implicite, donc défait l'avantage de la lisibilité.

7 votes

Nous allons devoir accepter d'être en désaccord sur ce point, @JonSkeet. Une classe scellée pourrait avoir une longue lignée d'héritage elle-même. La complexité n'est pas contenue en la scellant. En fait, la sceller n'apporte rien à la lisibilité. C'est comme si vous vous référiez à Sealed comme "Locked" ou quelque chose comme ça. Le scellement empêche simplement l'héritage.

10voto

48klocs Points 3749

J'aime à penser que je suis un programmeur raisonnablement expérimenté et, si je n'ai rien appris d'autre, c'est que je suis remarquablement mauvais pour prédire l'avenir.

La saisie scellée n'est pas difficile, mais je ne veux pas irriter un développeur (qui pourrait être moi !) qui découvrirait qu'un problème pourrait être facilement résolu avec un peu d'héritage.

Je ne vois pas non plus comment le fait de sceller une classe la rend plus lisible. Essayez-vous de forcer les gens à préférer la composition à l'héritage ?

0 votes

+1 pour la reconnaissance de la difficulté de la précognition :)

14 votes

Vous avez raison, nous ne pouvons pas prédire l'avenir - alors pourquoi ne pas choisir l'option la moins restrictive, en termes de changements futurs ? Une fois que vous avez rendu une classe non scellée et que quelqu'un en a dérivé, vous ne pouvez plus changer cette décision. Si vous voulez desceller une classe plus tard, cela peut être fait sans rien casser. N'invitez pas les sous-classes jusqu'à ce que vous sachiez que vous en avez besoin - à ce moment-là, vous saurez que vous avez besoin d'une classe. pourquoi vous en avez besoin, vous pouvez donc concevoir cet aspect de l'héritage.

4 votes

Je ne suis pas nécessairement d'accord. Vous devez concevoir une classe avec la sous-classification en tête si vous voulez vraiment ajouter de la valeur à l'héritage. Quel est l'intérêt d'hériter d'une classe si vous avez le même accès à son état interne que si vous utilisiez simplement une relation 'has a'. La première implique l'utilisation d'un état protégé et d'un ensemble d'"outils" protégés, ce qui signifie que vous devez consciemment concevoir la classe en tenant compte de la sous-classification.

5voto

Yochai Timmer Points 19802

Il n'y a rien de mal à hériter d'une classe.

Vous ne devriez sceller une classe que lorsqu'il y a une bonne raison pour laquelle elle ne devrait jamais être héritée.

De plus, si vous les scellez tous, cela ne fera que diminuer la maintenabilité. Chaque fois que quelqu'un voudra hériter de l'une de vos classes, il verra qu'elle est scellée, puis il enlèvera le sceau (en manipulant du code qu'il ne devrait pas avoir à manipuler) ou pire : il créera une mauvaise implémentation de votre classe pour lui-même.

Vous aurez alors deux implémentations de la même chose, l'une probablement pire que l'autre, et deux morceaux de code à maintenir.

Il vaut mieux le garder non scellé. Il n'y a pas de mal à ce qu'il soit descellé.

5voto

InBetween Points 6162

Franchement, je pense que le fait que les classes ne soient pas scellées par défaut en C# est un peu bizarre et déplacé par rapport à la façon dont le reste des défauts fonctionnent dans le langage.

Par défaut, les classes sont internal . Par défaut, les champs sont private . Par défaut, les membres sont private .

Il semble qu'une tendance se dessine en faveur de l'accès le moins plausible par défaut. Il serait logique qu'un unsealed doit sortir en c# au lieu d'un mot-clé sealed .

Personnellement, je préférerais que les classes soient scellées par défaut. Dans la plupart des cas, lorsque quelqu'un écrit une classe, il ne la conçoit pas en pensant aux sous-classes et à toutes les complexités qui en découlent. La conception d'une future sous-classe devrait être un acte conscient et donc je préférerais que vous ayez à le déclarer explicitement.

0 votes

Il aurait été intéressant que C# exige l'abstraction pour hériter d'une classe (ou un autre mot clé pour indiquer qu'elle n'est pas scellée). Mais ce n'est pas ce qui s'est passé. Et je compte certainement sur l'héritage d'une classe sur un coup de tête ces jours-ci. Cela aurait pu être le cas. Je suis probablement heureux que ça ne se soit pas passé comme ça.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X