Komplette Arbeit der Klasse im Konstruktor aufrufen

runagrog

Commander
Registriert
März 2012
Beiträge
2.095
Moin,
ich habe eine Frage an euch: Ich schreibe grad zu Übungszwecken (in Java, wobei das eigentlich irrelevant sein sollte) ein kleines Programm und ich versuche das Problem durch objektorientierte Programmierung zu vereinfachen. Das Tolle ist, dass meine entsprechende Klasse immer das gleiche tut, und dass die eigentliche Arbeit immer direkt nach dem Konstruktor ausgeführt werden kann. Diese Arbeit geschieht mit einer rekursiven Methode, die ich also irgendwie das erste mal aufrufen muss.

Ich frage mich nun, ob ich diese rekursive Methode direkt im Konstruktor aufrufen soll? Zum einen spart das Schreibarbeit und außerdem spart es mir eine komplette Methode (und den entsprechenden Methodenaufruf), andererseits ist der Konstruktor meines Wissens wirklich nur dazu da, das Objekt zu erstellen und nicht die ganze Arbeit des Objekts zu erledigen.

Welche von beiden Lösungen würdet ihr aus designtechnischen Gründen vorziehen?
 
Soll es immer beim instantisieren des Objektes ausgeführt werden, kommt es in den Konstruktor, wenn nicht, dann nicht :D
 
Extra Konstruktor und extra Methode.
Weil mans einfach so machen soll.
 
Aussage gegen Aussage :D
Es soll wirklich immer danach ausgeführt werden, Netbeans warnt mich aber von wegen "Overridable Method Call in Constructor". Kann ich davon ausgehen, dass ich im Konstruktor keine Methoden der Klasse aufrufen sollte / kann?
 
Die Java Language Specification sagt dazu das:
Unlike C++, the Java programming language does not specify altered rules for method dispatch during the creation of a new class instance. If methods are invoked that are overridden in subclasses in the object being initialized, then these overriding methods are used, even before the new object is completely initialized.

Quelle: http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.5

Meiner Meinung nach sollten im Konstruktor nur Zuweisungen vorgenommen werden (Berechnungen nur, falls sie der Zuweisung dienen). Dafür ist der Konstruktor da. Er ist schließlich keine Methode. Wer das bei mir im Studium in der Programmier-Übung so gemacht hat, wie du es machen willst, bekam vom Prof immer eine auf den Deckel :D


Lässt man ewig lang Berechnungen im Konstruktor laufen, ist das Objekt erst fertig instantiiert, wenn die Berechnungen durch sind. Klingt für mich persönlich nicht so schön.
 
Zuletzt bearbeitet:
runagrog schrieb:
Aussage gegen Aussage :D
Es soll wirklich immer danach ausgeführt werden, Netbeans warnt mich aber von wegen "Overridable Method Call in Constructor". Kann ich davon ausgehen, dass ich im Konstruktor keine Methoden der Klasse aufrufen sollte / kann?

Man kann es so machen, aber es spricht nicht für sauberes Design und kann - deshalb die Warnung - zu Problemen führen, wenn man irgendwann erweitern möchte.

Wenn das Objekt nur dazu da ist, einmalig etwas auszuführen, warum überhaupt ein Objekt?
 
Ok, das lass ich das. Ich hab zwar keine Unterklassen (und werde auch mit Sicherheit keine brauchen), aber sauberer Code ist nie so richtig falsch. Die eigentliche Berechnung ist recht komplex (zumindest kommt sie mir so vor :D), deshalb versuch ich mir das Problem mit OOP einfacher zu machen.

Vielen Dank für die schnellen und hilfreichen Antworten!
 
Warum sollte dieser Fall durch OOP einfach werden? Hast du denn wirklich OBJEKTE, die etwas ausführen? So wie du es beschreibst: Nein. Deine Aufgabenstellung wird durch OOP weder übersichtlicher noch einfacher oder performanter. In einer Sprache, die so etwas zulässt, solltest du hier auf schlichte prozedurale Programmierung zurückgreifen.
 
Nun ja, so weit wie ich das beurteilen kann habe ich durchaus Objekte, die etwas ausführen, ich benötige in diesem bestimmten Fall nur keine Vererbung. Vielleicht liegt es auch an mir, aber ich stelle mir mein Problem objektorientiert einfacher lösbar vor. Ich habe verschiedene Zustände, die sich jeweils in vielen unterschiedlichen Punkten unterscheiden, und je nach diesen Punkten wird die Berechnung eines jeden Zustands anders durchgeführt. Diese Zustände versuche ich objektorientiert zu modellieren, und ich denke dass das übersichtlicher ist.
 
Mhhh, aber wenn deine Initialisierung-Methode immer das gleiche tut wie du schreibst, macht es vielleicht mehr Sinn diese Initialisierung nur einmal durchzuführen, z.B indem das Objekt das dass Ergebnis deiner Rekursiven Methode aufnimmt "static" wird, und Du im Kontruktor einfach testest ob das Objekt schon existiert.
Du sagst das du keine Vererbung brauchst, dann mach die Klassen "final". :)
 
Hmm, hört sich für mich so an, als ob du dir die Klasse völlig schenken kannst und die Funktion genausogut da einbinden kannst, wo sie aufgerufen wird. Wenn du das natürlich öfter benötigst kann ein eigenes Objekt dafür sinnvoll sein, oder optional auch ein 'Mischmasch' Objekt wo alle Funktionen reinkommen, die man öfter mal benötigt und die sonst jeweils eine eugene Klasse bräuchten. Das ist vielleicht nicht die feine englische Art, aber Imho kann man das durchsus machen wenn es die Arbeit erleichtert...
 
Hi,

es wäre vielleicht von Vorteil, könntest du uns sagen, welchen Sinn die Objekte der Klasse erfüllen. Für mich hört es sich generell (wie auch schon erwähnt) so an, als könntest du dir die Klasse sparen und mit einer (statischen) Methode arbeiten. Das wirkt sich wahrscheinlich auch besser auf die Laufzeiten und den Speicherverbrauch deines Programmes aus. Aber ohne genaue Beschreibung ist das eine Vermutung.

Beste Grüße
 
Vielleicht kannst du ja den relevanten Auszug aus deinen Beispielcode hier rein kopieren.
runagrog schrieb:
Ich schreibe grad zu Übungszwecken (in Java, wobei das eigentlich irrelevant sein sollte)
Ganz im Gegenteil: Auf Code-Ebene unterscheiden sich die Best-Practices z.T. erheblich von einer Sprache zur anderen
 
Der Quelltext ist leider sehr umfangreich, weshalb ich den hier eher nicht hineinkopieren würde. Aber es geht um eine Breitensuche: Beginnend mit einem Startpunkt können aus jedem Knoten weitere Knoten berechnet werden. Diese Berechnung ist von vielen Parametern abhängig, die dem Knoten bekannt sein müssen. Ich habe mir gedacht, jeden Knoten durch ein Objekt darzustellen, da ich so die Parameter gut speichern kann und da ich die Knoten alle speichern muss (Breitensuche), ist es mit einer statischen Methode nicht getan.
 
runagrog schrieb:
Der Quelltext ist leider sehr umfangreich, weshalb ich den hier eher nicht hineinkopieren würde.
Mit relevant meinte ich den Teil, den man braucht, um die Struktur des Algorithmus zu verstehen (kann z.B. auch größtenteils Pseudocode sein). Ich sag mal so: wenn sich das Problem nicht anhand von ein paar dutzend (Pseudo-)Codezeilen erklären lässt, dann wirst du hier vermutlich auch keine Antwort bekommen, die zu deinem Problem passt.

Generell spricht meiner Meinung nach nichts dagegen auch aufwändigere Arbeiten dirket im Konstruktor zu erledigen, wenn sie logisch ein Teil der Initialisierung des Objekts sind. Die rekursive Suche bzw. das Erzeugen und Hinzufügen von neuen Kindknoten gehört aber meiner Meinung nach nicht zur Initalisierung eines Knotens in einem Graph.

Ich finde da den c++ Ansatz recht einleuchtend: Algorithmen werden als Funktionen implementiert die (potentiell) auf Datenstrukturen arbeiten bzw. sich derer bedienen und sind nicht Teil dieser Struktur.
Das würde bedeuten, dass dein Suchalgorithmus on-the-fly den Suchbaum aufbauen würde und nicht, dass das Ergebnis der Suche ein "Nebenprodukt" der Erzeugung des Baumes ist.
Es kann aber gut sein, dass die Standardvorgehensweise unter Java anders aussieht.
 
Zuletzt bearbeitet: (Typos)
@Miuwa: Diese Vorgehensweise ist in Java eigentlich gleich (zumindest, soweit ich das als 1. Semester der Informatik bewerten kann).

Generell versuchst du ja eine Art Datenstruktur zu konstruieren. Generell konstruiert man die Datenstruktur und sorgt dafür, dass die Entsprechenden Klassen Methoden für sämtliche Vorgehen hat. Konstruiere ich beispielsweise einen Baum, Gibt es eine Klasse, die den Baum repräsentiert, eine Klasse die die Knoten (inkl. deren Kinder) repräsentiert. Wenn ich einen Knoten hinzufügen will, habe ich eine Methode Baum.add(Inputdatenobjekt) welche ein neues Objekt in beliebiger Weise hinzufügt.

Allerdings wäre das die exemplarische Hochschulvariante, ich weiß nicht, ob sich das in der Praxis prinzipiell so abbilden lässt. Generell hat Miuwa aber recht, einige Zeilen Pseudocode sind immer hilfreich.

Beste Grüße

PS: Nochmals, ich bin 1. Semestler und nicht sicher, ob meine Lösungen die besten auf dieser Welt sind.
 
Nein, was miuwa damit meinte, war daß in C++ die Funktionen (nicht Methoden), die die diversen Algorithmen implementieren, nicht Teil der Datenstrukturen (auf denen sie operieren) selbst sind sondern freie Funktionen, die die Datenstrukturen als Parameter übergeben bekommen. So hat zum Beispiel in C++ nicht die vector-Klasse eine sort-Methode und die list-Klasse eine sort-Methode und dann die deque-Klasse noch mal eine sort-Methode, sondern es gibt eine frei sort-Funktion, die sowohl mit vector als auch mit list und deque (und allen anderen geordneten Containern in der C++-Standardbibliothek) arbeiten kann. Der Container wird der Funktion über Iteratoren auf den Anfang und das Ende des zu sortierenden Container-Bereichs übergeben.

Ich bin kein Java-Programmierer, aber ich glaube in Java ist es eher so, daß die verschiedenen Container die diversen Algorithmen alle selber implementieren, also als Methoden (korregiert mich, falls ich da falsch liege).
 
Zuletzt bearbeitet:
antred schrieb:
Ich bin kein Java-Programmierer, aber ich glaube in Java ist es eher so, daß die verschiedenen Container die diversen Algorithmen alle selber implementieren, also als Methoden (korregiert mich, falls ich da falsch liege).

Yap, damit liegst Du falsch. Es wäre zwar möglich, die Sortierung in den Klassen zu handeln, aber Java bietet dafür eine separate Utility-Klasse, die auch noch weitere Features bereitstellt: java.util.Collections.
 
Normal zerlegt man Code in Sinngemäße Strukturen.

Konstruktor: Alles was intern in der Klasse gemacht wird, z.B. Variablen zuweisen, Eigenschaften setzen
Methoden: Alle logischen Teilabschnitte die eigenständig funktionieren und einfach per Aufruf gestartet werden
Main: Steuerung des Programms.

Würde also nicht alles in den Konstruktor laden, sondern eine Methode start() erstellen, dann aus der main() Klasse.start aufrufen. So weiß man sofort beim Code betrachten was passiert. Braucht man diesen Prozess öfter, dann machst dir eine Hilfsmethode in der Main die dies erledigt und dir ein Objekt der Klasse liefert.

Direkt beim instanzieren (new...) der Klasse eine Rekursion zu starten ist unschön. Da geht die Kontrolle und Lesbarkeit flöten. Generell sind lange Rekursionen in Java gefährlich und eher zu vermeiden. Von static usw. rate ich ab - es hebelt die Objektorientierung aus. Ist das Programm lang, dann wird es immer wirrer zu tracken was mit den static Dingen gemacht wird, da jede Veränderung, egal woher, Auswirkung auf alles andere hat. So etwas zu warten ist zum kotzen, deswegen wurde Objektorientierung erfunden.
 
Zuletzt bearbeitet:
Zurück
Oben