Question

En java, est-il jamais un cas pour permettre à une classe non abstraite à être prolongée?

Il semble toujours indiquer le code mauvais quand il y a des hiérarchies de classes. Acceptez-vous, et pourquoi / pourquoi pas?

Était-ce utile?

La solution

Je suis d'accord avec Jon et Kent mais, comme Scott Myers (en C ++ efficace), je vais beaucoup plus loin. Je crois que toutes les classes doivent être soit abstract, ou final . À savoir, seules les classes de feuilles dans une hiérarchie sont vraiment aptes à instanciation directe. Toutes les autres classes (à savoir noeuds internes dans l'héritage) sont « inachevé » et doit donc être <=>.

Il est tout simplement pas de sens pour les classes habituelles à plus étendues. Si un aspect de la classe vaut l'extension et / ou la modification, la plus propre serait de prendre qu'une classe et le séparer en une classe de base et <=> une mise en œuvre interchangeable concrète.

Autres conseils

Il y a certainement des moments où il est logique d'avoir des classes concrètes non-finales. Cependant, je suis d'accord avec Kent - Je crois que les classes devraient être finales (scellé en C #) par défaut, et que les méthodes Java devrait être définitive par défaut (comme dans C #)

.

Comme le dit Kent, l'héritage exige une conception soignée et documentation - il est très facile de penser que vous pouvez simplement remplacer une seule méthode, mais ne pas connaître les situations où cette méthode peut être appelée à partir de la classe de base dans le cadre du reste de la la mise en œuvre.

Voir « Comment concevoir une classe pour l'héritage » pour plus de discussion à ce sujet.

Cette question est également applicable à d'autres plates-formes telles que C # .NET. Il y a ceux (moi y compris) qui croient types doivent être finale / scellé par défaut et doivent être descellé explicitement pour permettre l'héritage.

Extension par héritage est quelque chose qui a besoin d'une conception soignée et n'est pas aussi simple que laisser un type non scellé. Par conséquent, je pense qu'il devrait être une décision explicite pour permettre l'héritage.

a de bonnes raisons de garder votre code non final. de nombreux cadres tels que mise en veille prolongée, le printemps, Guice dépendent parfois des classes non finales qu'ils dynamiquement lors de l'exécution étend.

par exemple, mise en veille prolongée utilise des procurations pour paresseux Peuplement d'associations. en particulier en ce qui concerne AOP, vous voulez que votre classe non finale, de sorte que les intercepteurs peuvent attacher. voir aussi la question de au SO

La meilleure référence ici est l'article 15 de l'excellent livre « Effective Java » de Joshua Bloch, appelé « Conception et documents pour l'héritage ou bien l'interdire ». Toutefois, la clé de savoir si l'extension d'une classe devrait être autorisée n'est pas « est-il abstrait », mais « était-il conçu avec l'héritage à l'esprit ». Il y a parfois une corrélation entre les deux, mais il est le deuxième qui est important. Pour prendre un exemple simple la plupart des classes AWT sont conçus pour être étendu, même ceux qui ne sont pas abstraites.

Le résumé du chapitre de Bloch est que l'interaction des classes héritées de leurs parents peuvent surprendre et si unpredicatable l'ancêtre n'a pas été conçu pour être hérité de. Les cours devraient donc venir en deux types de classes a) conçu pour être étendu, et avec assez de documentation pour décrire la façon dont il doit être fait b) Les classes marquées finale. Les classes en (a) seront souvent abstraite, mais pas toujours. Pour

Dans certains cas, vous voulez vous assurer qu'il n'y a pas subclassing, dans d'autres cas, vous voulez vous assurer subclassing (résumé). Mais il y a toujours un grand sous-ensemble de classes où vous l'auteur original ne se soucient pas et ne doit pas prendre soin. Cela fait partie d'être ouvert / fermé. Décider que quelque chose doit être fermé est aussi à faire pour une raison.

Je suis en désaccord. Si les hiérarchies étaient mauvaises, il n'y aurait aucune raison pour que des langages orientés objet d'exister. Si vous regardez les bibliothèques widget interface utilisateur de Microsoft et Sun, vous êtes certain de trouver l'héritage. Est-ce que tous les « mauvais code » par définition? Non, bien sûr que non.

L'héritage peut être abusé, mais ne peut donc aucune fonction de la langue. L'astuce consiste à apprendre à faire correctement les choses.

Je ne pouvais pas être plus en désaccord. hiérarchies de classe ont un sens pour les classes concrètes lorsque les classes concrètes connaissent les types de retour possibles des méthodes qui n'ont pas marqué final. Par exemple, une classe de béton peut avoir un crochet de la sous-classe:

protected SomeType doSomething() {
return null;
}

Cette doSomething est guarenteed être soit nul ou une instance de UnType. Dites que vous avez la possibilité de traiter l'instance UnType mais ne dispose pas d'un cas d'utilisation pour l'utilisation de l'instance UnType dans la classe actuelle, mais sachez que cette fonctionnalité serait vraiment bon d'avoir dans les sous-classes et la plupart tout est concret. Il n'a pas de sens de faire la classe actuelle une classe abstraite si elle peut être utilisée directement avec le défaut de ne rien faire avec sa valeur nulle. Si vous l'avez fait une classe abstraite, alors que vous auriez ses enfants dans ce type de hiérarchie:

  • Classe de base abstraite
    • classe par défaut (la classe qui aurait pu être non abstraite, ne met en œuvre la méthode protégée et rien d'autre)
    • D'autres sous-classes.

Vous avez donc une classe de base abstraite qui ne peut pas être utilisé directement, lorsque la classe par défaut peut être le cas le plus courant. Dans l'autre hiérarchie, il y a une moins classe, de sorte que la fonctionnalité peut être utilisée sans une classe par défaut essentiellement inutile parce que l'abstraction devait juste être forcé sur la classe.

  • classe par défaut
    • D'autres sous-classes.

Maintenant, bien sûr, les hiérarchies peuvent être utilisés et abusés, et si les choses ne sont pas documentées clairement ou des classes pas conçus, sous-classes peuvent rencontrer des problèmes. Mais ces mêmes problèmes existent avec les classes abstraites aussi bien, vous ne vous débarrassez pas du problème juste parce que vous ajoutez « abstrait » à votre classe. Par exemple, si le contrat de la méthode « doSomething () » ci-dessus UnType nécessaire pour avoir peuplé x, y et champs z quand ils ont été consultés via des accesseurs, votre sous-classe éclaterait peu importe si vous avez utilisé la classe concrète qui est retourné null que votre classe de base ou une classe abstraite.

La règle générale pour la conception d'une hiérarchie de classes est à peu près d'un simple questionnaire:

  1. Ai-je besoin de mon comportement superclasse proposé dans ma sous-classe? (O / N) Ceci est la première question que vous devez vous poser. Si vous n'avez pas besoin du comportement, il n'y a aucun argument pour subclassing.

  2. Ai-je besoin de mon état superclasse proposé dans ma sous-classe? (O / N) Ceci est la deuxième question. Si l'état correspond au modèle de ce que vous avez besoin, cela peut être un canidate pour subclassing.

  3. Si la sous-classe a été créée à partir des superclasse proposées, serait-il vraiment une IS-une relation, ou est-ce juste un raccourci pour hériter le comportement et l'état? Ceci est la dernière question. S'il est juste un raccourci et vous ne pouvez pas qualifier votre sous-classe proposée « as-a » superclasse, alors l'héritage doit être évité. L'état et la logique peuvent être copiés et collés dans la nouvelle classe avec une racine différente, ou la délégation peuvent être utilisés.

Seulement si une classe a besoin le comportement, l'état et peut être considéré que la sous-classe-A (n) instance de la superclasse doit-il être considéré comme hériter d'une superclasse. Dans le cas contraire, d'autres options existent qui serait mieux adapté au but, même si elle peut exiger un peu plus de travail à l'avant, il est plus propre à long terme.

Il y a quelques cas où nous ne voulons pas permettre de changer le comportement. Par exemple, la classe String, Math.

Je n'aime pas l'héritage parce qu'il ya toujours une meilleure façon de faire la même chose, mais quand vous apportez des modifications de maintenance dans un énorme système parfois la meilleure façon de corriger le code avec un minimum de changements est d'étendre une classe un peu . Oui, il est conduit généralement à un mauvais code, mais à un travail et sans mois de réécriture d'abord. Donnant ainsi un homme d'entretien autant de flexibilité qu'il peut gérer est une bonne façon d'aller.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top