Vorgehen Projekt (Klassenstruktur)

Guntpat1981

Mitglied
Hallo zusammen,

ich beginne heute ein größeres Projekt und wollte zunächst einmal Rat von erfahrenen Java-Programmierern einholen, was die Vorbereitung eines Projektes angeht.

Dies soll mein Programm leisten:

1.) Erstellen einer Ordnerstruktur (1 Hauptordner und 5 Unterordner sollen erstellt werden).
2.) Durch das Parsen einer vorgegebenen XML-Konfigurationsdatei werden verschiedene Dateien erstellt (XML-Dateien, andere Java-Dateien etc.), welche sich nach dem Programmdurchlauf in den Ordnern wiederfinden.

Ich wollte nun eigentlich nur mal fragen, ob jemand Tipps bezüglich der Klassenstruktur hat. Also welche Klassen werde ich wohl benötigen und welche Aufgaben werden diese wohl haben. Ich weiß, dass ihr über die Interna des Projektes nichts wisst, aber ich möchte einfach nur vermeiden, dass ich eventuell zu wenige Klassen habe, die mit Funktionalität überfrachtet sind. Ich suche nach einer sinnvollen Art und Weise, mein Projekt zu ordnen.

Ich würde mich freuen, ein paar Kommentare von Euch zu erhalten.

Viele Grüße,
Guntpat
 

Dario Linsky

Erfahrenes Mitglied
Hi,

so pauschal lässt sich das nicht sagen. Wenn gewisse Funktionen inhaltlich und sinngemäß einer Entität zuzuordnen sind, würde ich eben diese Funktionen mit in die Klasse kapseln, die diese Entität darstellt. Zum Beispiel gehören keine Funktionen, die Produkte betreffen in die Klasse, die den Kunden abstrahiert. Da gibt es in der Regel aber mehrere Möglichkeiten, die durchaus alle richtig sind. Wichtig ist nur, dass das Zusammenspiel der verschiedenen Klassen konsistent bleibt.

Wenn du dir unsicher bist, mach doch einfach erstmal ein UML-Klassendiagramm (oder sowas ähnliches) und spiel das Szenario im Kopf durch. Wenn du da auf Ungereimtheiten stößt, solltest du die Aufteilung nochmal überdenken.

Bei kleineren Projekten halte ich es aber ohnehin für überflüssig, mit Entwurfsmustern und anderen OO-Prinzipien anzurücken.

Grüße, D.
 

Oliver Gierke

Erfahrenes Mitglied
Bei kleineren Projekten halte ich es aber ohnehin für überflüssig, mit Entwurfsmustern und anderen OO-Prinzipien anzurücken.

Das halte ich für fragwürdig. Natürlich wird niemand anfangen und sagen: für zwei Klassen fange ich jetzt mit einem Observer an. Wobei man ja auch meistens nicht explizit ein Pattern auswählt und das dann ausprogrammiert, sondern diese sowieso aus dem Bauch heraus auswählt bzw. die sich eigentlich oft von selbst herleiten. Jedes Interface ist ja quasi schon ein Strategypattern im weitesten Sinne.

@Originalposter: du hast recht, ohne detailliertes Insiderwissen ist es schwer Tipps zu geben. Wenn du aber viel mit dem Dateisystem arbeiten musst, macht es sicher Sinn, diesen Zugriff zu abstrahieren. In den Apache Commons Bibliothekten gibt es eine Menge Support für etwas umfangreichere Aufgaben, wie Ordner kopieren, Ordner rekursiv löschen usw. Die muss man daher nicht unbedingt selbst auf die File API "draufsetzen".

Grundsätzlich ist testbarer Code immer guter Code. D.h. wenn du darauf achtest, dass es nicht schwer ist, Testfälle für deinen Code zu schreiben, du recht sicher sein kannst, dass dein Code nicht sooo schlecht ist ;). Dependency Injection ist so ein "Pattern", dass Testbarkeit stark vereinfacht und somit guten Code unterstützt. Nicht von dem Begriff abschrecken lassen, der auf den ersten Blick vielleicht gleich nach Spring und damit nach "zu umfangreich für mein kleines Projekt" aussieht. Eine einfache Factoryklasse reicht auch für den Anfang ;).

Gruß
Ollie
 

takidoso

Erfahrenes Mitglied
hi,
wie Guntpat1981kann ich bestätigen, dass man für eine Klassenaufteilung erheblich mehr Infos bezüglich Deines Vorhabens benötigt.
Allgemein lass ich mich allermeist von sprachlichen Einteilungen/Konstrukten leiten, da man diese dann intuitiver als Außenstehender wiedererkennen kann.
Falls Du aus welchen Gründen auch immer auch Ableitungshierachien verwenden solltest, bitte leite nicht rein funktional ab, also nach dem Motto: die Funktion, die die Klasse "lala" hat ist toll ich mach mir jetzt daraus ein "hmhmhm", sondern schaue bei Möglichkeit immer, ob die Klasse von der Du ableiten möchtest ein Oberbegriff ist von der Klasse, die Du dann daraus machen willst.
Simples Beispiel: Ich habe eine Klasse Hund und möchte aber eine Klasse Katze. Die Katze von Hund abzuleiten, ist technisch sicher möglich, wäre aber was die Wiedererkennung angeht nicht sonderlich toll, denn eine Katze ist nunmal kein spezieller Hund ;-). Schöner wäre dann lieber eine Oberklasse zu definieren, die Hunde und Katzen vereint, sprich zum Oberbegriff haben (hier vieleicht Säugetier)
Neben der ist-Beziehung, die Oberbegriff und "Unterbegriff" zum Ausdruck bringen sool, gibt es oft auch die "hat-Beziehung". Während bei Ist-Bezihungen Ableitung der Normalfall ist, sollte man bei hat-Beziehungen aggregieren (Object besteht beinhaltet und verwendet anderes Objekt).
Ein Kuli ist ein Stift
aber...
Ein Kuli hat eine Mine, hat eine Feder, hat ein Hüllenoberteil, hat ein Hüllenunterteil, hat einen Mechanismus zum Vorbringen des Minenkopfes.
 
Zuletzt bearbeitet:

Oliver Gierke

Erfahrenes Mitglied
Alles richtig was takidoso schreibt. Vererbung wirklich nur (eigentlich sogar nicht unbedingt immer) wenn es eine "is a" Beziehung gibt.

REINHAUN!
 

takidoso

Erfahrenes Mitglied
Mit der Befürchtung, dass ich mich jetzt zu sehr auslasse, aber ich habe (leider) Software in der Wartung, die unglücklicherweise "Hat-Beziehung" oder (wie ich es gerne auch nenne) lockeren "Benutzungs-Beziehungen" mit hierachischen Ableitungen realisiert. Der ursprüngliche Autor war ein C++ Programmierer. Da C++ Mehrfachvererbung erlaubt, wird dies in gewisserweise verziehen bzw. man wird als Programmierer vielleicht sogar dazu verführt. Konkret in diesem Beispiel
erbt ein Fachobjekt von einem Logger und dieser erbt von einem "Parameterleser". Aus meiner Sicht ist das so, als würde man aus einer Garage ein Auto machen. Technisch funktioniert es, aber ist, was Wartungsfreundlichkeit angeht, herzlich unglücklich.
  1. Es entspricht nicht einer einigermaßen intuitiven Sicht, ist für Außenstehende nicht auf Anhieb zu verstehen.
  2. Die am Ende der Hierachie stehende Klasse (Fachklasse) hat unglaublich viele absolut nicht fachspezifische ererbte Methoden, Diskretion wird nicht geward.
  3. Sollte man von fremden Bibliotheken erben müssen könnte man in diesem Beispiel den Logger nicht mehr so verwenden wie man es gewohnt war
  4. Vor lauter Membern innerhalb einer Klasse werden Member-Lookuplisten einer IDE aufgelbäht und vermindern die Effiziens der IDE-Unterstüzung

Alles richtig was takidoso schreibt. Vererbung wirklich nur (eigentlich sogar nicht unbedingt immer) wenn es eine "is a" Beziehung gibt.

REINHAUN!

Mal aus Neugier und der Vollständikeit halber, Oliver, kannst Du ein Beispiel geben, wann es besser wäre trotz einer Ist-Beziehung nicht abzuleiten? Meinst Du damit vielleicht die Verwendung von Interfaces?
 

Oliver Gierke

Erfahrenes Mitglied
Mal aus Neugier und der Vollständikeit halber, Oliver, kannst Du ein Beispiel geben, wann es besser wäre trotz einer Ist-Beziehung nicht abzuleiten? Meinst Du damit vielleicht die Verwendung von Interfaces?

[offtopic]Ollie bitte, nicht so förmlich ;)[/offtopic]

Nun, grundsätzlich ist das Einführen einer Vererbungsbeziehung eine Designentscheidung. Und bei Designentscheidungen gibt es nie ein "auf X folgt Y" sonder es gilt immer "wir wählen X, weil Y". D.h. Designentscheidungen sollten irgendwie dokumentiert werden - das nur am Rande.

In einem aktuellen Projekt hatten wir ein sehr komplexes Domänenmodell, dass recht große Klassen hervorbrachte. Sie waren leider nicht mehr weiter aufzuteilen, da wir sehr oft recht unterschiedliche Teile der Funktionalität benötigten, so dass durch eine größere Aufteilung viel Erzeuge- und Datenkopieroperationen entstanden wären.

Durch die benötigte Logik wäre mit Vererbung zu den abstrakten Basisklassen, die eh schon locker 300 Zeilen lang waren noch locker weitere 300 Zeilen Code hinzugekommen bzw. eine Vererbungshierarchie mit 4 - 5 Stufen, wobei jede Klasse auch sehr groß geworden wäre. Hinzu kam die "Fessel" der Vererbung bzgl. der Superklasse. Subklassen mussten also in einen Teilbaum eingehangen werden, obwohl sie logisch in zwei gehört hätten. Ein weiterer Punkt ist die Erweiterbarkeit. Ein Interface anders zu Implementieren ist oft einfacher, als mitten in einem Vererbungsbaum eine Klasse einzuhängen. Da war Delegation dann das besser Mittel der Wahl. Aber wie gesagt, sowas hat Auswirkungen. Man muss z.B. den Objektgraphen traversieren, und kann nicht das Objekt direkt benutzen. Das ist zum Teil weniger schön. Alles in allem haben in unserem Fall aber die Vorteile der Delegation überwogen.

Wie gesagt - die Regel ist ein guter Anhaltspunkt. Allerdings sollte man durchaus auch mal alternative Entwürfe zu Ende denken und ausprobieren.

Gruß
Ollie
 

Neue Beiträge