Ich habe mehrere Klassen Parent
und Child1
... Child9
in Java implementiert. Parent
ist eine abstrakte Klasse, die alle allgemeinen Variablen der untergeordneten Klassen enthält (viel, was der Hauptgrund ist, warum ich Parent
eine abstrakte Klasse und keine Schnittstelle erstellt habe), einige abstrakte und einige implementierte Methoden.
Einige der untergeordneten Klassen verfügen über benutzerdefinierte Methoden, die für sie spezifisch sind. So oft rufe ich eine untergeordnete Methode mit Downcasting auf:
Parent p = new Child1();
((Child1) p).child1SpecificMethod();
Irgendwie habe ich das Gefühl, dass dies eine schlechte OOD-Praxis ist, aber ich bin mir nicht ganz sicher, ob dies wirklich der Fall ist bzw. wie das Design verbessert werden kann.
- Bearbeiten - Was ich wahrscheinlich sowieso ändern sollte, ist die Tatsache, dass ich die Parent-Klasse verwende, um viele (vorerst) allgemeine Variablen zu organisieren und sie (oder ein Containerobjekt) zu Mitgliedern der konkreten Klassen zu machen.
p
alsParent
? Das Festhalten an allgemeinen Typen ist eine gute Vorgehensweise für APIs und Rückgabetypen, jedoch nicht in demselben Bereich, in dem Sie selbst eine konkrete Klasse zuweisen.Antworten:
Dies ist nicht nur eine schlechte Praxis , dies ist auch unnötig kompliziert.
Warum verwenden Sie die Vererbung im Allgemeinen?
Wenn Sie die Vererbung verwenden, haben Sie ein gemeinsames Verhalten, das Sie für viele verschiedene Netzbetreiber verfügbar machen möchten. Dies umfasst sowohl die Klassenvererbung als auch die Schnittstellenvererbung . Der Erbe ist sozusagen oft eine Spezialisierung der Klasse, von der er erbt; Dies gilt hauptsächlich für die Klassenvererbung.
Denken Sie an eine Klasse Auto und einer Unterklasse porsche (die typische ist ein -Beziehung). Sie haben allgemeines Verhalten wie Starten / Stoppen des Motors , Lenken und so weiter. Wenn Sie einen Porsche wie ein Auto behandeln, sind Sie an diesen Aspekt seines Verhaltens gebunden. Wenn Sie wissen, dass Sie nur einen Porsche wollen und ihn nur als Porsche behandeln , ist es überflüssig, einen Porsche als Auto zu instanziieren und durch Casting ein Porsche-Verhalten zu erhalten .
Polymorphismus macht umgekehrt Sinn:
Sie haben einen Porsche und müssen ihn unter dem Gesichtspunkt eines Autos behandeln. zB fahren
Solange Ihr Porsche das Lenken nach links , Lenken nach rechts , Verschieben nach oben , Verschieben nach unten usw. akzeptiert , können Sie Polymorphismus / Substitution für einander verwenden.
Es ist besser, Ihre Objekte in ihrer speziellen Form zu instanziieren. Dann können Sie den Polymorphismus optimal nutzen und ihn nur dann verwenden, wenn Sie ihn benötigen .
Das heißt:
Parent p = new Child1();
macht für mich keinen Sinn.Edit: Ich würde Porsche anders (über Komposition ) implementieren , aber für das Beispiel ist es ein Auto.
quelle
Ihr Gefühl ist richtig, es als schlechte Praxis zu betrachten. Stellen Sie sich Ihren Beispielcode etwas anders vor:
Woher weißt du, dass der Wert von p wirklich Child1 ist? Sie tun dies nicht und dies kann zur Laufzeit eine ClassCastException verursachen. Wenn Sie child1SpecificMethod () in Ihrem Code aufrufen müssen, müssen Sie sicherstellen, dass p vom Typ Child1 ist. Wenn dies nicht möglich ist, weil Objekt p als Typ Parent an Ihren Code übergeben wird (z. B. als Methodenparameter), können Sie eine Variante des Besuchermusters verwenden und child1SpecificMethod in der Handle-Methode Ihres Besucherobjekts ausführen, die behandelt wird Kind1.
quelle
Verwenden Sie stattdessen die Suche nach Funktionen. Geben Sie keinen Zugriff auf die untergeordneten Klassen, betrachten Sie sie als Implementierungen der übergeordneten Klasse.
Definieren Sie dann Schnittstellen, die bestimmte Funktionen und Merkmale angeben.
Verwendungszweck:
Dieser Erkennungsmechanismus ist sehr flexibel. Die Verwendung von Delegierung anstelle von Vererbung kann sehr lohnend sein. Beachten Sie, dass untergeordnete Klassen nicht mehr benötigt werden.
Oder in Java 8 (wo mehrere Variationen möglich sind und die Schnittstelle auch funktionsfähig sein könnte):
Machen Sie in der Parent-Klasse eine Suche nach Funktionen:
Oder in Java 8:
Die Kinderklasse:
Oder dynamischer:
quelle
Fügen Sie eine abstrakte Methode child1SpecificMethod () in die übergeordnete Klasse ein (Sie müssen die Klasse als abstrakt markieren) und stellen Sie ihre Implementierung in der jeweiligen untergeordneten Klasse bereit.
quelle