Si tout va bien pas trop académique ...
Disons que j'ai besoin de nombres réels et complexes dans ma bibliothèque SW.
Basé sur la relation is-a (ou ici ), le nombre réel est un nombre complexe, où b dans la partie imaginaire du nombre complexe est simplement 0.
D'un autre côté, mon implémentation serait que cet enfant étend le parent, donc dans le parent RealNumber, j'aurais une partie réelle et l'enfant ComplexNumber ajouterait de l'art imaginaire.
Il y a aussi une opinion, que l' héritage est mauvais .
Je me souviens comme hier, quand j'apprenais la POO à l'université, mon professeur a dit, ce n'est pas un bon exemple d'héritage car la valeur absolue de ces deux est calculée différemment (mais pour cela nous avons une surcharge de méthode / polymorfisme, non?) .. .
Mon expérience est que nous utilisons souvent l'héritage pour résoudre DRY, par conséquent, nous avons souvent des classes abstraites artificielles dans la hiérarchie (nous avons souvent du mal à trouver des noms car ils ne représentent pas des objets d'un monde réel).
la source
Réponses:
Même si dans un sens mathématique, un nombre réel est un nombre complexe, ce n'est pas une bonne idée de dériver le réel du complexe. Il viole le principe de substitution de Liskov en disant (entre autres) qu'une classe dérivée ne doit pas cacher les propriétés d'une classe de base.
Dans ce cas, un nombre réel devrait masquer la partie imaginaire du nombre complexe. Il est clair que cela n'a aucun sens de stocker un nombre à virgule flottante caché (partie imaginaire) si vous n'avez besoin que de la partie réelle.
Il s'agit essentiellement du même problème que l'exemple rectangle / carré mentionné dans un commentaire.
la source
Ce n'est pas en fait une raison impérieuse contre tout héritage ici, juste le modèle
class RealNumber
<-> proposéclass ComplexNumber
.Vous pouvez raisonnablement définir une interface
Number
, qui à la foisRealNumber
etComplexNumber
implémenterait.Cela pourrait ressembler
Mais vous voudriez alors contraindre les autres
Number
paramètres de ces opérations à être du même type dérivé que celuithis
que vous pouvez approcher avecOu à la place, vous utiliseriez un langage qui permettait le polymorphisme structurel, au lieu du polymorphisme de sous-type. Pour le cas spécifique des nombres, il se peut que vous n'ayez besoin que de surcharger les opérateurs arithmétiques.
la source
Solution: ne pas avoir de
RealNumber
classe publiqueJe trouverais cela tout à fait correct si
ComplexNumber
j'avais une méthode d'usine statiquefromDouble(double)
qui retournerait un nombre complexe avec un imaginaire égal à zéro. Vous pouvez ensuite utiliser toutes les opérations que vous utiliseriez sur uneRealNumber
instance sur cetteComplexNumber
instance.Mais j'ai du mal à voir pourquoi vous voudriez / devriez avoir une
RealNumber
classe héritée publique . L'héritage est généralement utilisé pour ces raisons (hors de ma tête, corrigez-moi si vous en manquez)étendre le comportement.
RealNumbers
ne peut pas faire d'opérations supplémentaires, un nombre complexe ne peut pas le faire, donc inutile de le faire.implémenter un comportement abstrait avec une implémentation spécifique. Puisque
ComplexNumber
ne doit pas être abstrait, cela ne s'applique pas non plus.réutilisation du code. Si vous utilisez simplement la
ComplexNumber
classe, vous réutilisez 100% du code.mise en œuvre plus spécifique / efficace / précise pour une tâche spécifique. Cela pourrait être appliqué ici,
RealNumbers
pourrait implémenter certaines fonctionnalités plus rapidement. Mais alors cette sous-classe doit être cachée derrière le statiquefromDouble(double)
et ne doit pas être connue à l'extérieur. De cette façon, il n'aurait pas besoin de cacher la partie imaginaire. Pour l'extérieur, il ne devrait y avoir que des nombres complexes (qui sont des nombres réels). Vous pouvez également renvoyer cette classe RealNumber privée à partir de toutes les opérations de la classe de nombres complexes qui aboutissent à un nombre réel. (Cela suppose que les classes sont immuables comme la plupart des classes numériques.)C'est comme implémenter une sous-classe d'Integer qui s'appelle Zero et coder en dur certaines des opérations car elles sont triviales pour zéro. Vous pouvez le faire, car chaque zéro est un entier, mais ne le rendez pas public, cachez-le derrière une méthode d'usine.
la source
Dire qu'un nombre réel est un nombre complexe a plus de sens en mathématiques, en particulier en théorie des ensembles, qu'en informatique.
En mathématiques, nous disons:
Cependant, cela ne signifie pas que vous devez, ou même devez, utiliser l'héritage lors de la conception de votre bibliothèque pour inclure une classe RealNumber et ComplexNumber. In Effective Java, Second Edition de Joshua Bloch; Le point 16 est "Favoriser la composition plutôt que l'héritage". Pour éviter les problèmes mentionnés dans cet élément, une fois que vous avez défini votre classe RealNumber, elle peut être utilisée dans votre classe ComplexNumber:
Cela vous donne toute la puissance de réutiliser votre classe RealNumber pour garder votre code SEC tout en évitant les problèmes identifiés par Joshua Bloch.
la source
Il y a deux problèmes ici. La première est qu'il est courant d'utiliser les mêmes termes pour les types de conteneurs et les types de leur contenu, en particulier avec les types primitifs comme les nombres. Le terme
double
, par exemple, est utilisé pour décrire à la fois une valeur à virgule flottante double précision et un conteneur dans lequel une valeur peut être stockée.Le deuxième problème est que si les relations is-a entre les conteneurs à partir desquels différents types d'objets peuvent être lus se comportent de la même manière que les relations entre les objets eux-mêmes, celles entre les conteneurs dans lesquels différents types d'objets peuvent être placés se comportent en face de celles de leur contenu. . Chaque cage connue pour contenir une instance de
Cat
sera une cage qui contient une instance deAnimal
, mais ne doit pas nécessairement être une cage qui contient une instance deSiameseCat
. D'un autre côté, chaque cage pouvant contenir toutes les instances deCat
sera une cage pouvant contenir toutes les instances deSiameseCat
, mais ne doit pas nécessairement être une cage pouvant contenir toutes les instances deAnimal
. Le seul type de cage qui peut contenir toutes les instances deCat
et peut être garanti ne peut jamais contenir autre chose qu'une instance deCat
, est une cage deCat
. Tout autre type de cage serait soit incapable d'accepter certains exemples deCat
ce qu'il devrait accepter, soit serait capable d'accepter des choses qui ne sont pas des exemples deCat
.la source