Ich habe in letzter Zeit an C1 viel verbessert, was das Fehlerverhalten angeht. Dabei ist mir ein Hilfsmittel zugute gekommen: Ich habe an vielen Stellen static Modifier entfernt.
Was der Vorteil davon ist, merkt man, wenn man die Nachteile von fehlgeschlagenen static-Initialisierungen bedenkt. Schlägt die Initialisierung eines static-Feldes einer Klasse (Klassenvariable) fehl, so kann die Klasse nicht geladen werden. Zuerst erhält man einen ExceptionInInitializerError. Folgeversuche, die Klasse doch noch zu laden, schlagen mit ClassNotFoundExceptions fehl.
Das ist natürlich für ein Serversystem nix. Da sollte es schon möglich sein, temporär fehlgeschlagene Aktionen später nochmal zu probieren. Das geht dann natürlich nicht mehr, sobald erst mal eine Klasseninitialisierung fehlgeschlagen ist.
Die Lösung liegt auf der Hand: Die Klasseninitialisierung darf nie fehlschlagen. Objektinitialisierung (Instanzierung) darf ruhig schief gehen, und das sollte sie auch. Denn, das ist eines der besten Entwicklungsmuster, die es gibt. Konstruktoren müssen penibelstens ihre Argumente prüfen und auf Fehler reagieren, und zwar immer sofort mit einer Exception.
Was bedeutet das? Dann existiert das Objekt nicht. Schade? Ganz im Gegenteil. Übergeht der Konstruktor Fehler, wird das Objekt erstellt und kann verwendet werden. Jedoch führen die Fehler dazu, dass das Objekt nun nicht vollständig sauber initialisiert ist.
Da gibt es nun viele Tricks, mit denen man arbeiten könnte, so wie ein property isInitialized(), in sämtlichen Methoden geprüft werden muss.
Dabei ist es so einfach: Wird die Erzeugung von Objekten in inkonsistentem Zustand gar nicht erst zugelassen, ist so etwas nicht ansatzweise nötig.
Ich predige immer wieder die Kapselung, und die ist es auch hier wieder, um die es geht, und die ein ordentliches Maß an Robustheit ausmacht.
Keine Methode einer Klasse darf ungültige Argumente akzeptieren. Man sollte auch nicht davon ausgehen, dass der Programmierer, der die Klasse benutzen muss, das schon alles richtig machen wird. Wird er nämlich nicht, man selbst kriegt das nicht gebacken. Deshalb, sobald ungültige Parameter übergeben werden, raus da!
Beispiel: so nich
1: public void checkObject(MyObj aObj) {
2: if (aObj.myFunc()) { // bang bang, my baby shot me down...
3: }
4: }
und so hier bitte auch nicht, das ist unnötiger Spaghetti-Code
1: public void checkObject(MyObj aObj) {
2: if (null != aObj) {
3: aObj.myFunc();
4:
5: } else {
6: throw new IllegalArgumentException(
7: "aObj must not be null.");
8: }
9:}
So wird's gemacht:
1:public void checkObject(MyObj aObj) {
2: if (null == aObj) {
3: throw new IllegalArgumentException("aObj must not be null.");
4: }
5:
6: aObj.myFunc();
7:
8:}
Deshalb nie static verwenden? Nein. Ganz ohne kommt man nicht aus. Ich habe aber festgestellt, dass man weitgehend drauf verzichten kann.
Natürlich braucht man an manchen Stellen doch den "static" Modifier, weil man zeitaufwändige Berechnungen und Ladevorgänge nicht mehrfach durchführen will und Ergebnisse cachen möchte.
Es ist allerdings sehr angenehm in der Handhabung ist, nur ganz wenige zentrale Singleton-Klassen zu erstellen, die Instanzen für andere Serviceklassen im Speicher halten und per Static-Getter zurückliefern.
Das ist besser als wenn jede der Serviceklassen selbst ein Singleton ist. Es gibt ja dann eine zentrale Stelle, an der auch entschieden werden kann, ob eine Serviceklasse mal weggeworfen wird, um Speicher freizugeben - der ist wird von statischen Objekten natürlich belegt.
Sylphen ist ein IT-Systemhaus mit Niederlassungen in Gießen, Frankfurt und Hamburg und unterstützt Sie
durch Berater und Programmierer bei der effizienten Software-Entwicklung im Bereich
Java, SQL und Integration. Unter 0641-94468-0 oder
info@sylphen.com beraten wir Sie gerne
unverbindlich.
zurück zu Customer-Solutions