Remplacement par exemple de Java?

10

Je suis donc relativement nouveau dans la programmation dans le monde réel (en dehors des projets académiques) et j'ai rencontré de nombreux articles disant que l'utilisation instanceofest une mauvaise chose à utiliser pour déterminer la classe d'un objet spécifique.

Ma situation est que j'ai trois classes, une classe de produits de base, une qui se prolonge et une autre qui se prolonge. Ceux-ci sont tous stockés dans la même table dans une base de données et j'ai du code qui doit utiliser les méthodes de chacun pour extraire des données.

Quelle est la meilleure pratique pour contourner cette façon de procéder? J'ai lu certaines choses sur le polymorphisme mais je ne trouve aucun exemple qui résout le problème que j'ai. Ils remplacent tous généralement une méthode qui, pour moi, ne fonctionnera pas car j'ai besoin de tirer différentes choses des différents objets.

Y a-t-il une meilleure façon de le faire ou suis-je coincé avec l'utilisation instanceofou une sorte de réflexion pour obtenir les champs spécifiques aux objets?

Thomas Mitchell
la source
10
Ce n'est pas que le mot instanceof- clé est faux; essayer de trouver la classe d'un objet est généralement le problème. Pas toujours faux, mais probablement dans votre cas. Peut-être que si vous nous dites ce que vous essayez d'accomplir, nous pouvons suggérer une solution utilisant le polymorphisme.
Andres F.
2
D'accord, chaque classe a des données qui lui sont spécifiques. Je veux en extraire les données spécifiques. Je pense avoir réalisé la réponse avec l'aide que j'ai eue. Quelque chose comme une méthode appelée getSpecifics()qui est implémentée différemment sur chacun, chacun renvoyant les données spécifiques à la classe?
Thomas Mitchell

Réponses:

16

La raison instanceofest découragée parce que ce n'est pas la POO.

Il ne devrait y avoir aucune raison pour que l'appelant / l'utilisateur d'un objet sache de quelle classe concrète il s'agit, au-delà de quel type de variable il est déclaré.

Si vous avez besoin d'un comportement différent dans les sous-classes, ajoutez une méthode et implémentez-les différemment.

monstre à cliquet
la source
1
Donc, une méthode getSpecifics()(ou quelque chose de similaire) sur chaque classe qui renverra les détails de chaque classe. Est-ce la meilleure approche?
Thomas Mitchell
@Schmooo Vous devez vraiment réfléchir à l'emplacement des fonctionnalités communes dans l'arbre des classes et aux contrats qui existent à chaque niveau.
3
Mais qu'en est-il d'un cas où votre objet traverse des couches et les informations de type sont perdues? Exemple je crée un List. Je le passe à un objet qui en prend Iterable. Maintenant, ce deuxième objet le passe à un troisième objet qui prend soit un Listpour l'optimisation, soit un Iterablemais est beaucoup plus lent. Le second ne devrait pas savoir que c'est une liste, mais le troisième aimerait bien le savoir. Le troisième objet ne devrait-il pas vérifier par exemple pour voir s'il peut appliquer l'optimisation? Voir par exemple la goyave FluentIterablequi fait exactement cela.
Laurent Bourgault-Roy
1
Je dirais que ce n'est pas toujours le cas que vous devez ajouter la méthode à la classe. Par exemple, certains codes reçoivent une exception et sont censés en faire quelque chose en fonction de leur type. Dites, faites un rapport ou faites quelque chose pour récupérer d'une erreur. Ce type de fonctionnalité ne convient certainement pas aux exceptions. Ou, si les classes proviennent d'une bibliothèque externe, vous n'avez même pas les moyens de modifier ces classes. Dans ce cas, je pense qu'il est absolument valable de s'appuyer sur le instanceof.
Malcolm
9

instanceof n'est pas nécessairement une mauvaise chose, mais c'est quelque chose que l'on devrait regarder.

Un exemple où cela fonctionne correctement est dans un endroit où l'on obtient une collection du type de base et où vous ne voulez que ceux d'un sous-type. Récupérer les adresses réseau de NetworkInterface.getNetworkInterfaces()retourne les objets NetworkInterface qui ont une collection d'objets InetAddress, dont certains sont Inet4Address et certains sont Inet6Address. Si l'on veut filtrer la collection pour les objets Inet4Address, il faut utiliser instanceof.

Dans la situation décrite dans le message d'origine, il existe une classe de base, quelque chose qui étend cette classe de base et quelque chose qui étend la classe étendue. Bien que n'étant pas complètement informatif, cela semble avoir les fondements d'une conception moins qu'idéale.

Lorsque vous renvoyez une classe de base, sauf s'il existe de bonnes raisons pour qu'elle soit conçue de cette manière (compatibilité descendante entre les spécifications d'une version antérieure), vous ne devriez pas essayer de jeter un œil aux types sous-jacents. Si vous recevez un ensemble, vous savez que vous obtenez un ensemble. Il permet au développeur de changer plus tard d'avis pour retourner un type plus spécifique (SortedSet) ou changer le type sous-jacent (HashSet en TreeSet) sans casser quoi que ce soit.

Repensez votre conception de la façon dont les objets sont structurés et parentés pour voir si l'on peut faire un meilleur modèle de classe qui ne nécessite pas de distinction de types.


la source
Il est possible que l'interface spécifie une isOfType(SomeEnum.IPv4)méthode pourrait être un meilleur moyen de filtrer de telles qualités que d'inspecter le type de béton via instanceof. Et si vous souhaitez diviser votre classe d'implémentation IPv4 plus tard? Non pas que ce soit toujours mieux, mais c'est une considération.
Steven Schlansker
@StevenSchlansker Cela pourrait fonctionner pour cette classe spécifique. Mais que se passe-t-il si l'on a besoin d'inspecter le type concret pour voir si un cast est possible (ou serait-il simplement cast et intercepter l'exception?) Inet6Address implémente plus de méthodes qu'InetAddress. Il lui serait difficile de travailler avec des interfaces (une énumération qui énumère chaque classe du package? Ou chargeur de classe?) Et cela signifierait que la méthode devrait être implémentée à la main (ou un code de réflexion dans Object). Considérez comment faire (o instanceof Serializable) || (o instanceof Externalizable). instanceof est meilleur que l'alternative
1

Vous pouvez utiliser la méthode getClass ().

Êtes-vous sûr d'avoir besoin de trois classes différentes? Peut-être qu'une classe avec un interrupteur à l'intérieur servira mieux?

Gangnus
la source
7
getClasset instanceofpartager les inconvénients. Le polymorphisme est meilleur que les deux lorsqu'il convient, et je ne vois pas qu'il ne correspond pas au cas d'utilisation d'OP.
Je n'ai rien contre ta première phrase. Mais le deuxième - désolé, je ne comprends pas du tout ce que vous voulez dire.
Gangnus
1
Avec getClassje ne partage toujours pas le même problème que l'utilisation instanceof? Je devrai toujours trouver ce que j'ai, puis appeler un ensemble de fonctions. Idéalement, je veux une méthode qui renvoie les données spécifiques à cette classe sans avoir besoin de transtyper en cet objet.
Thomas Mitchell
Je me plains que vous ignoriez le polymorphisme, car c'est souvent un meilleur choix. Je suis presque sûr que le cas d'utilisation dans la question peut être fait avec le polymorphisme, donc je ne vois pas la nécessité d'utiliser non plus. (En dehors de cela, reproduire la réponse de quelqu'un d'autre n'est pas bien.)
2
@Gangus Je ne considère pas cela comme une "attaque", je veux dire pas d'offense. Mais peu importe. Non, la question n'est pas "quoi d'autre peut être utilisé", c'est "y a-t-il une meilleure façon de le faire". À moins que vous ne vouliez dire que getClassc'est une meilleure façon de le faire, cela n'a rien à voir avec la plupart des réponses ;-)
1

Typiquement, quand je me retrouve à vouloir connaître le type de quelque chose, cela signifie que j'ai mal mis en œuvre ma structure d'objet. La plupart du temps, cela revient à violer le LSP .

Il y a des moments cependant où je souhaite avoir un moyen de faire une répartition dynamique et d'économiser une tonne de code de plaque de chaudière et de pérenniser ma structure d'objet. C # fournit le mot-clé dynamique dans les versions les plus récentes du framework mais pour autant que je sache, Java n'a toujours pas quelque chose de similaire.

Cela dit, instanceof est généralement meilleur que de comparer des classes car il supportera correctement l'héritage. Vous pouvez également utiliser des méthodes telles que isAssignableFrom et d'autres de l'API de réflexion. Si vous voulez implémenter quelque chose comme la répartition dynamique, cela peut être fait via l'API de réflexion mais attention, ce sera lent. À utiliser avec prudence, idéalement, si possible, vous devez corriger la structure de l'objet et la conception de votre application.

J'espère que cela t'aides

Newtopian
la source