Wie erstelle ich ein "abstraktes Feld"?

8

Ich weiß, dass abstrakte Felder in Java nicht existieren. Ich lese auch diese Frage , aber die vorgeschlagenen Lösungen werden mein Problem nicht lösen. Vielleicht gibt es keine Lösung, aber es lohnt sich zu fragen:)

Problem

Ich habe eine abstrakte Klasse, die eine Operation im Konstruktor abhängig vom Wert eines ihrer Felder ausführt. Das Problem ist, dass sich der Wert dieses Feldes abhängig von der Unterklasse ändert. Wie kann ich dies tun, dass die Operation auf den Wert des von der Unterklasse neu definierten Feldes durchgeführt wird?

Wenn ich das Feld in der Unterklasse einfach "überschreibe", wird die Operation für den Wert des Feldes in der abstrakten Klasse ausgeführt.

Ich bin offen für jede Lösung, die sicherstellen würde, dass die Operation während der Instanziierung der Unterklasse ausgeführt wird (dh die Operation in eine von jeder Unterklasse im Konstruktor aufgerufene Methode einzufügen ist nicht a gültige Lösung, weil jemand die abstrakte Klasse erweitern und vergessen könnte, die Methode aufzurufen).

Ich möchte auch nicht den Wert des Feldes als Argument des Konstruktors angeben.

Gibt es eine Lösung, oder soll ich einfach mein Design ändern?

Bearbeiten:

Meine Unterklassen sind tatsächlich einige Werkzeuge, die von meinem Hauptprogramm verwendet werden, also muss der Konstruktor öffentlich sein und genau die Argumente nehmen, mit denen sie aufgerufen werden:

%Vor%

(die Unterklassen sind Hand, Pencil und AddObject, die alle die abstrakte Klasse Tool erweitern)

Deshalb möchte ich den Konstruktor nicht ändern.

Die Lösung, die ich verwenden werde, ist, den obigen Code leicht zu ändern:

%Vor%

und verwenden Sie einen abstrakten Getter, um auf das Feld zuzugreifen.

    
Jules Olléon 10.04.2010, 13:49
quelle

8 Antworten

13

Wie steht es mit abstrakten Getter / Setter für Feld?

%Vor%     
Crozin 10.04.2010, 13:53
quelle
14
  

Ich möchte auch nicht den Wert angeben   des Feldes als Argument der   Konstruktor.

Warum nicht? Es ist die perfekte Lösung. Machen Sie den Konstruktor protected und bieten Sie keinen Standardkonstruktor an, und Unterklassenimplementierer müssen einen Wert in ihren Konstruktoren angeben, der öffentlich sein und einen konstanten Wert an die Oberklasse übergeben kann, wodurch der Parameter für Benutzer der Unterklassen unsichtbar wird. p> %Vor%     

Michael Borgwardt 10.04.2010 14:32
quelle
2

Wie wäre es mit dem Template-Muster?

%Vor%

Auf diese Weise erzwingen Sie, dass alle Unterklassen die Methode init() implementieren, die, da sie vom Konstruktor aufgerufen wird, das Feld für Sie zuweist.

    
matsev 10.04.2010 14:50
quelle
1

Sie können dies nicht im Konstruktor tun, da die Superklasse vor allem in der Unterklasse initialisiert wird. Der Zugriff auf Werte, die für Ihre Unterklasse spezifisch sind, schlägt in Ihrem Superkonstruktor fehl Erwägen Sie, eine Factory-Methode zum Erstellen Ihres Objekts zu verwenden. Zum Beispiel:

%Vor%

Sie haben ein Problem in diesem bestimmten Beispiel, in dem MyClass nicht unterklassifiziert werden kann, aber Sie könnten den Konstruktor geschützt machen. Stellen Sie sicher, dass Ihre Basisklasse einen öffentlichen / geschützten Konstruktor auch für diesen Code hat. Es soll nur veranschaulichen, dass Sie wahrscheinlich zwei Schritte Initialisierung für was Sie tun möchten Eine andere mögliche Lösung, die Sie verwenden könnten, ist die Verwendung einer Factory-Klasse, die alle Varianten dieser abstrakten Klasse erstellt, und Sie könnten das Feld in den Konstruktor übergeben. Ihre Fabrik wäre die einzige, die das Feld kennt und die Benutzer der Fabrik könnten sich dessen nicht bewusst sein.

BEARBEITEN: Auch ohne die Factory können Sie Ihrer abstrakten Basisklasse das Feld im Konstruktor zuweisen, so dass alle Unterklassen bei der Instanziierung einen Wert an sie übergeben müssen. p>     

NG. 10.04.2010 14:15
quelle
1
  

Ich möchte auch nicht den Wert des Feldes als Argument des Konstruktors angeben.

     

Gibt es eine Lösung, oder soll ich einfach mein Design ändern?

Ja, ich denke, Sie sollten Ihr Design ändern, damit die Unterklasse den Wert an den Konstruktor übergibt. Da der Unterklassenabschnitt Ihres Objekts nicht initialisiert wird, bis nach der Superklassenkonstruktor zurückgegeben wurde, gibt es wirklich keinen anderen sauberen Weg, dies zu tun. Sicher, das würde funktionieren:

%Vor%

..., da die Implementierung von abstractField() nicht auf den Objektzustand wirkt. Sie können jedoch nicht garantieren, dass Unterklassen es nicht für eine gute Idee halten, etwas dynamischer zu sein, und abstractField() gibt einen nicht konstanten Wert zurück:

%Vor%

Dies funktioniert nicht so, wie Sie es erwarten würden, da die Initialisierer und Konstruktoren von Unterklassen denen der Oberklasse folgen. Sowohl new Sub2() als auch new Sub3(42) würden Abstract field: 0 drucken, da die value Felder nicht initialisiert wurden, wenn abstractField() aufgerufen wurde.

Das Übergeben des Werts an den Konstruktor hat außerdem den zusätzlichen Vorteil, dass das Feld, in dem Sie den Wert speichern, final sein kann.

    
gustafc 10.04.2010 14:38
quelle
1

Wenn der Wert vom Typ der Unterklasse bestimmt wird, warum brauchen Sie überhaupt ein Feld? Sie können eine einfache abstrakte Methode verwenden, die implementiert wird, um für jede Unterklasse einen anderen Wert zurückzugeben.

    
Peter Lawrey 10.04.2010 14:38
quelle
0

Ich denke, Sie benötigen eine Factory ("virtueller Konstruktor"), die auf diesen Parameter einwirken kann.

Wenn es in einer bestimmten Sprache schwierig ist, denken Sie wahrscheinlich falsch darüber nach.

    
duffymo 10.04.2010 13:50
quelle
0

Wenn ich Sie richtig verstehe: Sie möchten, dass der Konstruktor der abstrakten Klasse abhängig von einem Feld in der abstrakten Klasse etwas tut, aber (hoffentlich) von der Unterklasse gesetzt wird?

Wenn ich das falsch verstanden habe, kannst du aufhören zu lesen ...

Aber wenn ich es richtig verstanden habe, dann versuchst du etwas zu tun, das unmöglich ist. Die Felder einer Klasse werden in lexikalischer Reihenfolge instanziiert (und wenn Sie also Felder "unter" oder "nach" deklarieren, werden diese Konstruktoren dann nicht instanziiert, bevor der Konstruktor aufgerufen wird). Darüber hinaus durchläuft die JVM die gesamte Oberklasse, bevor sie irgendetwas mit der Unterklasse tut (weshalb der Aufruf "super ()" im Konstruktor einer Unterklasse die erste Anweisung im Konstruktor sein muss, weil dies lediglich "Ratschlag" ist die JVM zur Ausführung des Konstruktors der Superklasse).

So beginnt eine Unterklasse erst dann zu instanziieren, wenn die Oberklasse vollständig instanziiert wurde (und der Konstruktor der Oberklasse zurückgegeben wurde).

Und deshalb können Sie keine abstrakten Felder haben: Ein abstraktes Feld würde in der abstrakten Klasse (aber nur in der Unterklasse) nicht existieren und ist daher ernsthaft (!) "ausgeschlossen" für die super (abstrakte) Klasse ... weil die JVM keine Referenzen auf das Feld binden kann (weil es nicht existiert).

Hoffe, das hilft.

    
Vilnis Krumins 24.02.2014 05:00
quelle