Ersatz zum Beispiel für Java?

10

Ich bin also ziemlich neu in der Programmierung in der realen Welt (außerhalb von akademischen Projekten) und habe viele Beiträge gesehen, die besagen, dass die Verwendung instanceofeine schlechte Sache ist, um festzustellen, welche Klasse ein bestimmtes Objekt ist.

Meine Situation ist, dass ich drei Klassen habe, eine Basisproduktklasse, eine, die sich darüber erstreckt, und eine andere, die sich darüber erstreckt. Diese sind alle in derselben Tabelle in einer Datenbank gespeichert, und ich habe Code, der die Methoden für jede verwenden muss, um Daten von ihnen abzurufen.

Was ist die beste Vorgehensweise, um diese Vorgehensweise zu umgehen? Ich habe einige Dinge über Polymorphismus gelesen, kann aber keine Beispiele finden, die das Problem beheben, das ich habe. Sie alle überschreiben normalerweise eine Methode, die für mich nicht funktioniert, da ich verschiedene Dinge aus den verschiedenen Objekten ziehen muss.

Gibt es einen besseren Weg, dies zu tun, oder bin ich bei der Verwendung instanceofoder einer Art Reflexion festgefahren , um die für die Objekte spezifischen Felder zu erhalten?

Thomas Mitchell
quelle
10
Es ist nicht so, dass das Schlüsselwort instanceoffalsch ist; Der Versuch, die Klasse eines Objekts zu finden, ist normalerweise das Problem. Nicht immer falsch, aber wahrscheinlich in Ihrem Fall. Wenn Sie uns mitteilen, was Sie erreichen möchten, können wir möglicherweise eine Lösung mit Polymorphismus vorschlagen.
Andres F.
2
Okay, jede Klasse hat spezifische Daten. Ich möchte die spezifischen Daten aus diesen ziehen. Ich glaube, ich habe die Antwort mit meiner Hilfe realisiert. So etwas wie eine Methode namens getSpecifics(), die auf jeder Methode unterschiedlich implementiert ist und bei der die für die Klasse spezifischen Daten zurückgegeben werden?
Thomas Mitchell

Antworten:

16

Der Grund instanceofist entmutigt, dass es nicht OOP ist.

Es sollte keinen Grund für den Aufrufer / Benutzer eines Objekts geben, zu wissen, um welche konkrete Klasse es sich handelt, ab welchem ​​Typ die Variable deklariert ist, als die es deklariert ist.

Wenn Sie in Unterklassen ein anderes Verhalten benötigen, fügen Sie eine Methode hinzu und implementieren Sie sie anders.

Ratschenfreak
quelle
1
Also eine Methode getSpecifics()(oder ähnliches) für jede Klasse, die die Details für jede Klasse zurückgibt. Ist das der beste Ansatz?
Thomas Mitchell
@Schmooo Sie müssen wirklich darüber nachdenken, wo die gemeinsame Funktionalität im Klassenbaum vorhanden ist und welche Verträge auf jeder Ebene vorhanden sind.
3
Aber was ist mit einem Fall, in dem Ihr Objekt Ebenen überschreitet und die Typinformationen verloren gehen? Beispiel Ich erstelle eine List. Ich gebe es an ein Objekt weiter, das eines nimmt Iterable. Jetzt übergibt dieses zweite Objekt es an ein drittes Objekt, das entweder ein Listzur Optimierung benötigt oder ein, Iterableaber viel langsamer ist. Der zweite sollte nicht wissen, dass es eine Liste ist, aber der dritte würde es sehr gerne wissen. Sollte das dritte Objekt nicht beispielsweise prüfen, ob es die Optimierung anwenden kann? Siehe zum Beispiel Guave FluentIterable, die genau das tut.
Laurent Bourgault-Roy
1
Ich würde sagen, dass dies nicht immer der Fall ist, wenn Sie die Methode zur Klasse hinzufügen müssen. Zum Beispiel bekommt ein Code eine Ausnahme und soll je nach Typ etwas damit anfangen. Sagen wir, macht einen Bericht oder unternimmt etwas, um Fehler zu beheben. Diese Art von Funktionalität passt definitiv nicht zu den Ausnahmen. Wenn die Klassen aus einer externen Bibliothek stammen, haben Sie nicht einmal die Möglichkeit, diese Klassen zu ändern. In diesem Fall denke ich, dass es absolut gültig ist, sich auf das zu verlassen instanceof.
Malcolm
9

instanceof ist nicht unbedingt eine schlechte Sache, aber es ist etwas, das man sich ansehen sollte.

Ein Beispiel dafür, wo es richtig funktioniert, ist ein Ort, an dem man eine Sammlung des Basistyps erhält und nur die eines Subtyps haben möchte. Wenn Sie die Netzwerkadressen NetworkInterface.getNetworkInterfaces()von abrufen, werden NetworkInterface-Objekte zurückgegeben, die eine Sammlung von InetAddress-Objekten enthalten, von denen einige Inet4Address und andere Inet6Address sind. Wenn die Auflistung nach Inet4Address-Objekten gefiltert werden soll, muss instanceof verwendet werden.

In der Situation, die im ursprünglichen Beitrag beschrieben wird, gibt es eine Basisklasse, die diese Basisklasse erweitert, und etwas, das die erweiterte Klasse erweitert. Dies ist zwar nicht vollständig informativ, scheint jedoch die Grundlage für ein weniger als ideales Design zu haben.

Wenn Sie eine Basisklasse zurückgeben, es sei denn, es gibt einen guten Grund dafür, dass sie so entworfen wurde (Abwärtskompatibilität zwischen Spezifikationen einer früheren Version), sollten Sie nicht versuchen, einen Blick auf die zugrunde liegenden Typen zu werfen. Wenn Sie ein Set zurückerhalten, wissen Sie, dass Sie ein Set erhalten. Es ermöglicht dem Entwickler, später seine Meinung zu ändern, um einen spezifischeren Typ (SortedSet) zurückzugeben oder den zugrunde liegenden Typ (HashSet in TreeSet) zu ändern, ohne etwas zu beschädigen.

Überdenken Sie Ihr Design, wie die Objekte strukturiert und übergeordnet sind, um festzustellen, ob ein besseres Klassenmodell erstellt werden kann, für das keine Unterscheidung der Typen erforderlich ist.


quelle
Es ist möglich, dass die Angabe einer isOfType(SomeEnum.IPv4)Methode durch die Schnittstelle eine bessere Möglichkeit ist, nach solchen Eigenschaften zu filtern, als den Betontyp über zu überprüfen instanceof. Was ist, wenn Sie Ihre IPv4-Implementierungsklasse später aufteilen möchten? Nicht dass das immer besser ist, aber es ist eine Überlegung.
Steven Schlansker
@StevenSchlansker Das könnte für diese bestimmte Klasse funktionieren. Aber was ist, wenn man den konkreten Typ untersuchen muss, um festzustellen, ob eine Umwandlung möglich ist (oder würde man nur die Ausnahme umwandeln und abfangen?). Inet6Address implementiert mehr Methoden als InetAddress. Es wäre schwierig, mit Schnittstellen zu arbeiten (eine Aufzählung, die jede Klasse im Paket auflistet? Oder Klassenladeprogramm?), Und das würde bedeuten, dass die Methode von Hand implementiert werden müsste (oder ein Reflektionscode in Object). Überlegen Sie, wie es geht (o instanceof Serializable) || (o instanceof Externalizable). instanceof ist besser als die Alternative
1

Sie können die Methode getClass () verwenden.

Bist du sicher, dass du drei verschiedene Klassen brauchst? Vielleicht dient eine Klasse mit einem Schalter im Inneren besser?

Gangnus
quelle
7
getClassund instanceofNachteile teilen. Polymorphismus ist besser als beides, wenn er passt, und ich sehe nicht, dass er nicht zum Anwendungsfall von OP passt.
Ich habe nichts gegen deinen ersten Satz. Aber der zweite - Entschuldigung, ich kann nicht verstehen, was du überhaupt meinst.
Gangnus
1
Mit getClassteile ich nicht immer noch das gleiche Problem wie mit instanceof? Ich muss noch herausfinden, welche ich habe, und dann eine Reihe von Funktionen aufrufen. Idealerweise möchte ich eine Methode, die die für diese Klasse spezifischen Daten zurückgibt, ohne dass sie in dieses Objekt umgewandelt werden müssen.
Thomas Mitchell
Ich beschwere mich darüber, dass Sie Polymorphismus ignorieren, da dies oft eine bessere Wahl ist. Ich bin mir ziemlich sicher, dass der Anwendungsfall in der Frage mit Polymorphismus durchgeführt werden kann, daher sehe ich auch keine Notwendigkeit, ihn zu verwenden. (Abgesehen davon ist es nicht schön, nur die Antwort eines anderen zu reproduzieren.)
2
@ Gangus Ich halte das nicht für einen "Angriff", ich meine keine Beleidigung. Aber was auch immer. Nein, die Frage lautet nicht "Was kann noch verwendet werden?", Sondern "Gibt es einen besseren Weg, dies zu tun?". Es sei denn, Sie möchten argumentieren, getClassist ein besserer Weg, es zu tun, es hat nichts damit zu tun, die meisten Antworten aufzunehmen ;-)
1

Wenn ich die Art von etwas wissen möchte, bedeutet dies normalerweise, dass ich meine Objektstruktur falsch implementiert habe. In den meisten Fällen kommt es darauf an, LSP zu verletzen .

Es gibt jedoch Zeiten, in denen ich mir wünschte, ich hätte eine Möglichkeit, dynamisch zu versenden, eine Tonne Kesselplattencode zu speichern und meine Objektstruktur zukunftssicher zu machen. C # liefert das dynamische Schlüsselwort in den neueren Raten des Frameworks, aber meines Wissens hat Java noch nichts Ähnliches.

Allerdings ist instanceof im Allgemeinen besser als das Vergleichen von Klassen, da es die Vererbung ordnungsgemäß unterstützt. Sie können auch Methoden wie isAssignableFrom und andere aus der Reflexions-API verwenden. Wenn Sie so etwas wie einen dynamischen Versand implementieren möchten, kann dies über die Reflection-API erfolgen. Beachten Sie jedoch, dass dies langsam ist. Verwenden Sie diese Option mit Vorsicht. Idealerweise sollten Sie die Objektstruktur und das Design Ihrer App korrigieren, wenn Sie können.

Hoffe das hilft

Newtopian
quelle