Hallo,
zwar bin ich kein Java-Anfänger, komme aber bei meinen bisherigen Projekten immer wieder an einen Punkt, den ich offenbar noch nicht verinnerlicht habe. Dazu ein Auszug aus dem Leitfaden der 12 häufigsten Anfänger-Fehler:
Das klingt erstmal simpel und könnte man schnell abhaken, nach dem Motto "ja, ist schon klar".
Nachdem ich nun aber mein aktuelles Projekt schon mehrfach umgeworfen und neu strukturiert habe, bemerke ich immer wieder eines: ich arbeite ausschließlich in einem einzigen Paket, nahezu alle Klassen, Interfaces, Enums usw. sind paketsichtbar, bis auf die Klasse, über die die eigentliche Funktionalität aufgebaut wird (nicht die Hauptklasse des Projekts). Vom Ansatz her finde ich das logisch, aber ich würde gerne mehr aufteilen, einerseits zugunsten der Übersichtlichkeit, für die Wiederverwendbarkeit und ganz besonders für spätere Anpassungen, denn darüber stolpere ich immer wieder.
Meine grobe Planung sieht bisher so aus (für ein GUI-Programm). Die import-Anweisungen habe ich hier z.T. weggelassen.
Hauptklasse des Projekts, ausschließlich zu Testzwecken (wirklich nötig oder sinnvoll?)
Eigentlich Funktionsklasse, die das JFrame erzeugt
Global sichtbare Enumeration zum Steuern des Verhaltens
Verwalter-Klasse
SomeManager (z.B. zum Einlesen und Aufbereiten von XML-Dateien)
AbstractManager
Nun erzeugt meine Klasse GUIMain weitere GUI-Elemente, die bspw. von JPanel oder JDialog abgeleitete Klassen verwenden. Alle zusammen würde ich gerne auslagern in ein separates Paket, wie myproject.gui, bspw. auch, um es später in anderen Projekten wiederverwenden zu können, als public Klassen. Problem dabei ist, dass sich fast alle Klassen bei mir untereinander kennen und Kreuz- und Querverweise existieren, die diesen Ansatz unmöglich machen. Zum Beispiel ist immer irgendwo die Verwalter-Klasse Core eingebunden, was mir auch notwendig erscheint.
Weiter habe ich momentan von außen nur Zugriff auf den Konstruktor von GUIMain und Behavior-Enum. Das ist auch so gewünscht. Alles weitere läuft intern im Paket ab, und soll, wie oben beschrieben, auf (Unter-)Pakete ausgweitet werden.
Das Paket-Konzept war mir bis vor kurzem noch nicht völlig klar, aber wenn ich es richtig verstehe und so, wie die Eclipse IDE es im Package-Baum darstellt, steht jedes Paket für sich und Unterpakete analog zur Verzeichnisstruktur existieren gar nicht? Wenn das so wäre, würde ich erwarten, dass ich von einem Unterpaket aus Zugriff auf paketsichtbare Klassen des übergeordneten Paketes habe.
Sicher hinkt das Beispiel an der einen oder anderen Stelle, aber ich hoffe, es ist trotzdem verständlich.
Entspricht dieser Ansatz dem üblichen Vorgehen oder gibt es Verbesserungsbedarf?
Wie kann ich meine Klassen autarker gestalten, möglichst ohne dass sie sich untereinander kennen müssen? Also ohne die Source-Initialisierungen der Form new SomeClass(this);
Vielen Dank vorab!
Gerne auch Links zu guten Tutorials, die sich mit dem Thema befassen.
zwar bin ich kein Java-Anfänger, komme aber bei meinen bisherigen Projekten immer wieder an einen Punkt, den ich offenbar noch nicht verinnerlicht habe. Dazu ein Auszug aus dem Leitfaden der 12 häufigsten Anfänger-Fehler:
4. Nicht ausreichende Befassung mit Software-Entwurf und der Architektur
Das Sprachgefühl und die Syntax sind der erste Schritt. Inhaltliches Wissen rund um Methoden, Klassen und der gelieferten Bibliothek sind der zweite.
Die große Kunst bei der Software-Entwicklung ist aber nicht nur eine saubere Implementierung von Methoden. Viel schwieriger ist ein geeigneter Software-Entwurf, der auch später anpassbar ist, übersichtlich strukturiert und auf einer guten Architektur aufbaut. Es ist also wichtig, sich zusätzlich mit der Software-Architektur zu befassen. Das beinhaltet unter anderem auch Aspekte wie Design Patterns.
Das klingt erstmal simpel und könnte man schnell abhaken, nach dem Motto "ja, ist schon klar".
Nachdem ich nun aber mein aktuelles Projekt schon mehrfach umgeworfen und neu strukturiert habe, bemerke ich immer wieder eines: ich arbeite ausschließlich in einem einzigen Paket, nahezu alle Klassen, Interfaces, Enums usw. sind paketsichtbar, bis auf die Klasse, über die die eigentliche Funktionalität aufgebaut wird (nicht die Hauptklasse des Projekts). Vom Ansatz her finde ich das logisch, aber ich würde gerne mehr aufteilen, einerseits zugunsten der Übersichtlichkeit, für die Wiederverwendbarkeit und ganz besonders für spätere Anpassungen, denn darüber stolpere ich immer wieder.
Meine grobe Planung sieht bisher so aus (für ein GUI-Programm). Die import-Anweisungen habe ich hier z.T. weggelassen.
Hauptklasse des Projekts, ausschließlich zu Testzwecken (wirklich nötig oder sinnvoll?)
Java:
// (default package)
// import ...
public class Test {
public static void main(String[] args) {
// Zum Testen von Sichtbarkeiten
GUIMain app = myproject.GUIMain(null);
//app.Behavior.TYPE_1; // public visibility
}
}
Eigentlich Funktionsklasse, die das JFrame erzeugt
Java:
package myproject;
// import ...
public class GUIMain extends JFrame {
final Core core; // Verwalter-Klasse
private Behavior behavior;
private DocType docType;
public GUIMain(Behavior behavior) {
super();
this.behavior = (behavior != null) ? behavior : Behavior.TYPE_1; // lässt sich während der Laufzeit umstellen
this.core = new Core(this);
// weitere Initialisierungen, GUI aufbauen ...
}
}
Global sichtbare Enumeration zum Steuern des Verhaltens
Java:
package myproject;
public enum Behavior {
TYPE_1(32),
TYPE_2(64);
private Type(int v) {
this.v = v;
// weitere Initialisierungen ...
}
final private v;
// ggf. weitere Funktionalität
}
Verwalter-Klasse
Java:
package myproject;
class Core {
final GUIMain source;
final SomeManager someManager;
final AnotherManager anotherManager;
// ...
Core(GUIMain source) {
this.source = source;
this.someManager = new SomeManager(this);
this.anotherManager = new AnotherManager(this); // ohne Code-Beispiel, analog zu SomeManager
// ...
}
// Beispielmethode zur Erzeugung eines neuen Dokuments, wenn man im Menü von GUIMain auf "Datei/Neu" klickt
void registerNewDocument() {
if (this.someManager.hasDirectory()) {
// Dokument im bestehenden Verzeichnis anlegen ...
}
}
// weitere Verwaltungsmethoden ...
}
SomeManager (z.B. zum Einlesen und Aufbereiten von XML-Dateien)
Java:
package myproject;
class SomeManager extends AbstractManager {
SomeManager(Core core) {
super(core);
}
boolean hasDirectory() {
return true; // vereinfacht, hier natürlich sinnvolle Überprüfung, statt true ...
}
}
AbstractManager
Java:
package myproject;
abstract class AbstractManager {
protected Core core;
AbstractManager(Core core) {
this.core = core;
}
// ggf. weitere gemeinsame Funktionalität
}
Nun erzeugt meine Klasse GUIMain weitere GUI-Elemente, die bspw. von JPanel oder JDialog abgeleitete Klassen verwenden. Alle zusammen würde ich gerne auslagern in ein separates Paket, wie myproject.gui, bspw. auch, um es später in anderen Projekten wiederverwenden zu können, als public Klassen. Problem dabei ist, dass sich fast alle Klassen bei mir untereinander kennen und Kreuz- und Querverweise existieren, die diesen Ansatz unmöglich machen. Zum Beispiel ist immer irgendwo die Verwalter-Klasse Core eingebunden, was mir auch notwendig erscheint.
Weiter habe ich momentan von außen nur Zugriff auf den Konstruktor von GUIMain und Behavior-Enum. Das ist auch so gewünscht. Alles weitere läuft intern im Paket ab, und soll, wie oben beschrieben, auf (Unter-)Pakete ausgweitet werden.
Das Paket-Konzept war mir bis vor kurzem noch nicht völlig klar, aber wenn ich es richtig verstehe und so, wie die Eclipse IDE es im Package-Baum darstellt, steht jedes Paket für sich und Unterpakete analog zur Verzeichnisstruktur existieren gar nicht? Wenn das so wäre, würde ich erwarten, dass ich von einem Unterpaket aus Zugriff auf paketsichtbare Klassen des übergeordneten Paketes habe.
Java:
package myproject.gui; // Unterpaket?
//package myotherproject; // Variante ohne Unterpaket?
import myproject;
public class GUISomeDialog extends JDialog
{
private DocType docType;
public GUISomeDialog() {
super();
this.docType = DocType.DOC_TYPE_1; // DocType ist nicht sichtbar!
}
}
Java:
package myproject;
// nur paketsichtbar, weil so gewünscht
enum DocType {
DOC_TYPE_1,
DOC_TYPE_2,
DOC_TYPE_3;
}
Sicher hinkt das Beispiel an der einen oder anderen Stelle, aber ich hoffe, es ist trotzdem verständlich.
Entspricht dieser Ansatz dem üblichen Vorgehen oder gibt es Verbesserungsbedarf?
Wie kann ich meine Klassen autarker gestalten, möglichst ohne dass sie sich untereinander kennen müssen? Also ohne die Source-Initialisierungen der Form new SomeClass(this);
Vielen Dank vorab!
Gerne auch Links zu guten Tutorials, die sich mit dem Thema befassen.