2015-03-22 10 views
5

Ich frage mich, ob ich Objekttypen in sinnlose Klassen erstellen/zerlegen und ob es einen besseren Weg gibt, es zu tun.Erstellen von vielen Objekttypen/Klassen nur zur Verwendung von instanceof

sagen, ich habe die folgenden Klassen bekam (->erstreckt die höhere Klasse):

Vehicle class - takes care of movement and a default speed 
-->Car class - adds passengers 
-->-->ElectricCar class - a default constructor 
-->-->GasolineCar class - a default constructor 
-->-->HybridCar class - a default constructor 
-->Motorcycle class - a default constructor 
-->Bike class - a default constructor, overrides speed 
-->Segway class - a default constructor, overrides speed 

Wie Sie sehen können, sind sie meist Standardkonstruktoren. Also erstelle ich sie nur für den Fall, dass ich jemals eine instanceof bedingte Anweisung verwenden muss. Der Großteil meines Codes landet in der Fahrzeugklasse, weil ich versuche, in jeder Klasse den gleichen Code zu vermeiden. Außerdem sollte ich Fahrzeug abstrahieren, richtig? Ich erstelle niemals ein Fahrzeugobjekt.

Ist das OK oder gibt es einen besseren Weg?

+1

Ich interessiere mich für eine Art und Weise Sie verwenden wollen diese Klassen. – SMA

+2

hängt alles davon ab, wie Sie sie verwenden werden. Bisher ist mit deiner Struktur nichts falsch. Und Sie können es nicht nur als Beispiel verwenden, sondern beispielsweise auch für Methoden wie boollean needsPetrol() ... canHavePassengers(), die Sie in den Unterklassen implementieren, anstatt die Kette von if instanceof-Anweisungen zu verwenden. – Zielu

+0

Was versuchst du zu tun? – nom

Antwort

4

Erstens, solange der Code funktioniert und löst die Aufgabe zur Hand würde ich sagen, es ist "richtig" genug (also ja, es ist in Ordnung). Einige Leute ziehen es vor, anstelle von abstrakten Klassen Schnittstellen zu verwenden (weil Sie mehrere Schnittstellen implementieren können, aber nur direkt von einem Vorgänger ausgehen). Wenn Sie Java 8+ verwenden, können Sie außerdem die Methoden default zu den Schnittstellen hinzufügen. Andere Alternativen könnten eine Vehicle Klasse, aber ein VehicleTypeenum Feld für die Vehicle Klasse beinhalten.

+1

@Downvoter: Atleast teilen Sie Ihre Gedanken auch beim Downvoting. Es hilft der Community, Fortschritte zu machen, indem sie ihre Fehler kennt. –

+1

@nIcEcOw I * immer * schätze konstruktives Feedback und die Möglichkeit, meine Antworten zu verbessern. –

+0

Danke für den Rat, ich denke über den Enum/Staat als Alternative nach. Nur noch ein Punkt und ich kann einige Antworten auffrischen lol. – SmokeyTehBear

2

Es kommt alles auf die Frage, ob Sie jemals zwischen ElectricCars, GasolineCars usw. unterscheiden müssen. Wenn nicht, könnten Sie einfach alles in Fahrzeug oder Auto legen und Fahrzeug/Auto-Objekte erstellen.

Wenn es nicht beabsichtigt ist, Fahrzeugobjekte zu erstellen, dann ja, sollte es abstrakt markiert werden.

4

Es gibt nie so etwas wie "zu viele Klassen", solange Ihre Klassen sinnvoll sind und eine Funktion erfüllen. Es gibt jedoch so etwas wie pointless abstraction meiner Meinung nach.

Wenn Sie 100% sicher, dass Sie immer nur diese Klassen verwenden den Fahrzeugtyp (Zitat aus Ihrer Frage), um zu bestimmen,

ich jemals eine instanceof bedingte Anweisung

verwenden müssen

Dann möglicherweise Unterklassen als sinnlose Abstraktion qualifiziert. Verwenden Sie stattdessen eine Aufzählung, die Ihren Fahrzeugtyp beschreibt und weitergeht.

Wenn Sie jedoch Ihre Unterklassen für mehr als nur den Typ vorwegnehmen oder planen, ist es völlig in Ordnung, dies durch Unterklassen zu tun, und es ist in der Tat vorzuziehen, viele If/Else- oder Switch-Anweisungen in Ihrem Fahrzeug zu haben Klasse.

+0

Ok cool, so wie die Dinge jetzt sind, könnte ein Enum vorzuziehen sein. Vielen Dank. – SmokeyTehBear

4

Wie bereits in den Kommentaren und Antworten darauf hingewiesen: Es hängt alles davon ab, was Sie versuchen Modell dort.

Aber vor allem in Bezug auf die Absicht, die Sie erwähnt:

So sie nur für den Fall, Ich schaffe ich brauche immer eine Instanceof bedingte Anweisung zu verwenden.

Seien Sie vorsichtig damit. Sie sollten es vermeiden, das unterschiedliche Verhalten von Objekten abhängig von ihrem Typ zu modellieren. Dabei spielt es keine Rolle, ob die Typinformationen

  • implizit verfügbar über instanceof prüfen
  • explizit über ein Verfahren wie boolean isMotorCycle(), wie es in einem Kommentar vorgeschlagen
  • explizit über so etwas wie ein enum Type { ... } und ein switch über der Typ.

Sie alle leiden unter dem gleichen Problem: Wenn Sie eine neue Klasse/Typ Ihrer Hierarchie hinzufügen, dann müssen Sie alle Orte beschließen und zu aktualisieren, wo diese Art Informationen abgefragt wurde. Dies kann zu einem Alptraum werden.

Dort sind legitime Anwendungen für Typprüfungen. Aber wenn Sie mit dem Schreiben von Code am Ende, die häufig überprüft haben, wie diese

void recharge(Vehicle v) { 
    if (v instanceof ElectricCar) ((ElectricCar)v).attachPlug(); 
    if (v instanceof GasolineCar) ((GasolineCar)v).fillFuel(); 
    if (v instanceof Bike)  ((Bike)v).getDriver().takeRest(); 
    ... 
} 

dann ist dies ein starker Hinweis darauf, dass etwas mit Ihrer Hierarchie falsch ist. Es kann sein, dass die Basisklasse, Vehicle, einfach nicht stark genug ist. Im obigen Beispiel könnte man dann in Betracht ziehen, die recharge()-Methode in die Klasse Vehicle zu ziehen und sie einfach aufzurufen, wobei man sich auf die polymorphe Implementierung verlässt.

Es könnte im schlimmsten Fall auch sein, dass die Konzepte, die Sie zu modellieren versuchen, einfach zu unabhängig sind, um in einer einzigen Hierarchie kombiniert zu werden.


Sie haben erwähnt, dass Sie eine Kollisionserkennung für diese Objekte durchführen möchten. Das klingt wie Sie bereits eine Lösung wie diese Annäherung:

class Bike extends Vehicle { 
    @Override 
    void collideWith(Vehicle other) { 
     if (other instanceof Car) collideWithCar((Car)other); 
     if (other instanceof Segway) collideWithSegway((Segway)other); 
     ... 
    } 
} 

Es gibt elegantere Lösungen dafür. Vielleicht möchten Sie über das Problem im Zusammenhang mit Double Dispatch lesen, und vielleicht werfen Sie einen Blick auf die Strategy Pattern.


Allgemeiner über die Frage, ob man „zu viele Klassen“ haben, gibt es einige allgemeine Regeln fo Daumen.

Einer von ihnen ist die Interface Segration Principle, die besagt, dass Sie serval Client-spezifische Schnittstellen erstellen sollten, anstatt einer großen Schnittstelle, die alles tut und daher sonst nicht verwandte Methoden kombiniert. Sie haben also nicht "zu viele Klassen", solange jeder von ihnen einen Zweck erfüllt. Man könnte sich fragen:

  • Wer hat zwischen einem GasolineCar und einem ElectricCar zu unterscheiden?
  • Wer muss sich nur mit einer dieser Schnittstellen beschäftigen?
  • Wenn sie erstrecken sich beide die gleiche Basisklasse: Wer wird die Basisklasse in der Lage zu nutzen (oder wird jeder irgendwie die konkrete Umsetzung wissen müssen?)
+0

Vielen Dank für die eingehende Antwort. Ihr aufladen() - Beispiel ist vollkommen sinnvoll und beseitigt die bedingten Anweisungen, die ich sowohl mit den Ansätzen ** instanceof ** als auch isMotorcyle() verwendet habe. Und darum konnte ich meinen Kopf nicht umschließen und versuchen, es auf höchst polymorphe Weise zu machen. Es ist schwer für mich herauszufinden, wer die beste Herangehensweise empfohlen hat, weil es so viele Möglichkeiten gibt, aber alle Teile Ihrer Antwort scheinen genau richtig zu sein. – SmokeyTehBear