Quand et pourquoi scellerais-tu une classe?

87

En C # et C ++ / CLI, le mot-clé sealed(ou NotInheritableen VB) est utilisé pour protéger une classe de toute chance d'héritage (la classe ne sera pas héritable). Je sais qu'une caractéristique de la programmation orientée objet est l'héritage et je pense que l'utilisation de sealedva à l'encontre de cette fonctionnalité, elle arrête l'héritage. Y a-t-il un exemple qui montre les avantages sealedet quand il est important de l'utiliser?

Aan
la source

Réponses:

96
  1. Sur une classe qui implémente des fonctionnalités de sécurité, afin que l'objet d'origine ne puisse pas être "emprunté".

  2. Plus généralement, j'ai récemment échangé avec une personne chez Microsoft, qui m'a dit avoir essayé de limiter l'héritage aux endroits où cela avait vraiment tout son sens, car il devient coûteux en termes de performances s'il n'est pas traité.
    Le mot clé scellé indique au CLR qu'il n'y a pas de classe plus bas pour rechercher des méthodes, ce qui accélère les choses.

Dans la plupart des outils d'amélioration des performances sur le marché de nos jours, vous trouverez une case à cocher qui scellera toutes vos classes qui ne sont pas héritées.
Attention cependant, car si vous souhaitez autoriser les plugins ou la découverte d'assemblages via MEF, vous rencontrerez des problèmes.

Louis Kottmann
la source
3
Je voulais dire être prudent avec le scellement des classes dans les bibliothèques réutilisées, surtout si elles sont réutilisées par des tiers puis réintégrées (via MEF) dans la base de code. Votre base de code ne peut pas hériter d'une classe donnée, mais des tiers le feront.
Louis Kottmann
10
La raison n ° 1 semble vague mais, en supposant que nous n'écrivons pas la plupart du temps des «fonctionnalités de sécurité», cela signifie-t-il que la raison n ° 1 s'applique à peine? La raison n ° 2 concerne le réglage des performances. De quelle différence de performance parlons-nous? Sont-ils suffisamment importants pour justifier la modification de la définition d'une classe non sécurisée? Même si la réponse serait «oui», ce serait idéalement une option du compilateur, c'est-à-dire «générer du code optimisé pour toutes les classes non scellées», plutôt que de nous demander aux développeurs de modifier la base de code.
RayLuo
1
il devient coûteux en termes de performances s'il n'est pas traité est-ce même mesurable avec moins d'un nombre insensé de tests fous?
t3chb0t
4
Le cachetage est nul. Cela rend les tests plus difficiles - je voudrais me moquer de quelques classes ASP.NET avec FakeItEasy, mais je ne peux pas car elles sont scellées.
Warlike Chimpanzee
2
Je ne peux pas être plus d'accord avec @RayLuo. J'ai frappé à plusieurs reprises que les gens ont scellé leurs classes où la sécurité et les performances ne sont pas vraiment un problème. Leur "scellé" a simplement empêché mon besoin raisonnable de passer outre les classes, a rendu les choses beaucoup plus difficiles. Comme l'a dit Warlike Chimpanzee, se moquer d'une classe est si courant dans les tests.
ZZY
15

Un addendum à l'excellente réponse de Baboon :

  1. Si une classe n'est pas conçue pour l'héritage, les sous-classes peuvent rompre les invariants de classe . Cela ne s'applique vraiment que si vous créez une API publique, bien sûr, mais en règle générale, je scelle toute classe non explicitement conçue pour être sous-classée.

Dans le même ordre d'idées, applicable uniquement aux classes non scellées: toute méthode créée virtualest un point d'extension, ou du moins ressemble à un point d'extension. Déclarer des méthodes virtualdoit également être une décision consciente. (En C #, c'est une décision consciente; en Java, ce n'est pas le cas.)


EDIT : Quelques liens pertinents:

Notez également que Kotlin scelle les classes par défaut; son openmot-clé est l'opposé de Java finalou sealedde C # . (Pour être sûr, il n'y a pas d'accord universel sur le fait que c'est une bonne chose .)

Petter Hesselberg
la source
25
Les cours de scellement causent plus de maux de tête que d'avantages. J'ai continuellement trouvé des situations où les développeurs ont scellé des classes, me causant des heures de difficulté dans ce qui devrait être simple. Arrêtez les cours de scellement, vous n'êtes pas aussi spirituel que vous le pensez. Sceller les classes seulement si vous DEVEZ, et même alors, reconsidérer. Juste mon avis, en tant que gars qui doit gérer les classes scellées d'autres personnes que je ne peux pas éditer / desceller.
Gant Laborde
9
Le commentaire de @GantMan devrait en fait être considéré comme une des réponses à la question du PO, car il donne essentiellement une réponse comme "Quand? Pas du tout. Pourquoi? C'est la raison pour laquelle vous ne faites PAS cela." Accordez-vous que vous devriez re-publier votre commentaire en tant que réponse séparée, puis collecter des votes pour cela. :-)
RayLuo
1
Cela faisait-il référence à cette réponse: stackoverflow.com/a/7777674/3195477 ? Il vaut mieux y établir un lien que (seulement) nommer la personne
UuDdLrLrSs
2

Marquer une classe comme Sealedempêche la falsification de classes importantes qui peuvent compromettre la sécurité ou affecter les performances.

Plusieurs fois, sceller une classe a également du sens lorsque l'on conçoit une classe utilitaire avec un comportement fixe, que nous ne voulons pas changer.

Par exemple, l' Systemespace de noms dans C#fournit de nombreuses classes qui sont scellées, telles que String. S'il n'est pas scellé, il serait possible d'étendre ses fonctionnalités, ce qui pourrait être indésirable, car il s'agit d'un type fondamental avec une fonctionnalité donnée.

De même, structuresin C#sont toujours implicitement scellés. Par conséquent, on ne peut pas dériver une structure / classe d'une autre structure. Le raisonnement en est qu'ils structuressont utilisés pour modéliser uniquement des types de données autonomes, atomiques, définis par l' utilisateur, que nous ne voulons pas modifier.

Parfois, lorsque vous créez des hiérarchies de classes, vous souhaiterez peut-être limiter une certaine branche de la chaîne d'héritage, en fonction de votre modèle de domaine ou de vos règles métier.

Par exemple, a Manageret PartTimeEmployeesont tous deux des Employees, mais vous n'avez aucun rôle après les employés à temps partiel de votre organisation. Dans ce cas, vous souhaiterez peut-être sceller PartTimeEmployeepour éviter toute nouvelle ramification. D'un autre côté, si vous avez des employés à temps partiel à l'heure ou à la semaine, il peut être judicieux d'en hériter PartTimeEmployee.

Akshay Khot
la source
En quoi l'extension de la classe String serait-elle indésirable? La chaîne fonctionnerait toujours exactement comme elle le fait actuellement, et vous pourriez avoir une classe dérivée avec des fonctionnalités supplémentaires lorsque cela est souhaité, alors de quel problème parlez-vous?
Kevin Wells
Quel serait également l’intérêt de «plafonner» votre hiérarchie d’héritage? Cela signifierait que si jamais vous aviez besoin d'étendre cette hiérarchie, vous devrez d'abord desceller la classe parente, ce qui est tout simplement inefficace
Kevin Wells
Découvrez cet excellent article d'Eric Lippert et cette question SO .
Akshay Khot le
1
Même cette réponse se résume fondamentalement à "Pourquoi voudriez-vous dériver String?", Puis mentionne les raisons pour lesquelles vous pourriez vouloir dériver String (chaînes terminées par null par exemple) et dit que vous devriez simplement contourner ce problème sans héritage. Alors, pourquoi le rendre plus compliqué et devoir le contourner plus tard quand vous pouvez simplement le laisser descellé en premier lieu et laisser vos options ouvertes
Kevin Wells
Pour la deuxième question, l'objectif serait d'éviter les comportements indésirables (selon la logique métier). Il est plus facile pour unsealla classe plus tard, si nécessaire, de la sceller et de casser toutes les classes qui en dépendent.
Akshay Khot le
0

Je pense que cet article a un bon point, le cas spécifique était lorsque vous essayez de convertir une classe non scellée sur une interface aléatoire, le compilateur ne lance pas d'erreur; mais quand scellé est utilisé, le compilateur renvoie une erreur qu'il ne peut pas convertir. La classe scellée apporte une sécurité d'accès au code supplémentaire.
https://www.codeproject.com/Articles/239939/Csharp-Tweaks-Why-to-use-the-sealed-keyword-on-cla

brillant
la source
1
Un lien vers une solution est le bienvenu, mais veuillez vous assurer que votre réponse est utile sans elle: ajoutez du contexte autour du lien afin que vos collègues utilisateurs aient une idée de ce que c'est et pourquoi il est là, puis citez la partie la plus pertinente de la page que vous '' relier au cas où la page cible ne serait pas disponible. Les réponses qui ne sont guère plus qu'un lien peuvent être supprimées.
Baum mit Augen
Désolé, je n'avais pas l'intention de le publier comme réponse, mais cela ne semble pas lié à d'autres réponses et je ne sais pas où le mettre
strisunshine
1
J'ai édité l'article selon la suggestion. À l'origine, je voudrais juste contribuer sous un angle différent (peut-être), mais je n'ai eu qu'un vote négatif et nous n'avons pas encore parlé du contenu, est-ce que le -1 pourrait gentiment en indiquer la raison?
strisunshine