Mein erster Artikel in unserem Blog befasst sich gleich mit einem sehr technischen Thema aus der Softwareentwicklung und Java-Programmierung. Um keine Zeit mit Floskeln zu verlieren – anschnallen und los gehts!
Es gehört zur guten Praxis der Softwareentwicklung, Klassen zu entwerfen, die sich um genau eine Teilaufgabe des Programms kümmern. Derartige Klassen sind weniger komplex als Klassen, die sich mit mehreren Teilaufgaben befassen. Die Komplexität verschwindet aber nicht einfach, sondern sie wird nur nach außen – zwischen die Klassen – verlagert. Viele triviale Klassen ergeben also ein komplexes Netzwerk von Klassen.
Die Objekte müssen zusammenarbeiten, um größere Aufgaben zu erledigen. Viele Klassen können nicht ohne andere Klassen funktionieren. Diese Abhängigkeit kann man im Code ausdrücken. Ich verwende dazu gerne parametrisierte Konstruktoren. Wenn ein Benutzer einer Klasse sieht, dass es nur einen Konstruktor gibt und dieser die Übergabe bestimmter Paramter verlangt, dann weiß der Benutzer, dass er dort etwas übergeben sollte. Dem Benutzer bleibt ja kaum eine Wahl. Wenn er dem Kontruktor null-Referenzen übergibt, muss er mit Problemen rechnen, sofern dies nicht explizit erlaubt und dokumentiert wurde.
Konstruktoren sind also ein gutes Mittel, um kommunikativen Code zu schreiben und sicherzustellen, dass keine Objekte mit inkonsistenten Zuständen erzeugt werden können. Leider gibt es viele Frameworks, die mit Klassen ohne parameterlosen Konstruktor nicht umgehen können. Beispielsweise muss eine Klasse einen parameterlosen Konsruktor besitzen, um sich Java Bean nennen zu dürfen. Ein anderes prominentes Beispiel ist JPA. Man wird gezwungen, entweder einen entsprechenden Konstruktor einzubauen oder ein anderes Framework zu verwenden.
Es ist schwierig, automatisiert zu ermitteln, welche Parameter an einen Konstruktor übergeben werden sollten. Letzendlich geht es hier um das Thema Dependency Injection. Das soll an dieser Stelle reichen. Ansätze, parametrisierte Konstruktoren automatisiert und generisch aufzurufen, wären ein Thema für einen weiteren Artikel.
Es gibt Aufgaben für die es eine bessere Lösung geben könnte. Insbesondere bei der Speicherung von Daten durch ein Persistence Framework oder der Serialisierung von Daten zur Übertragung über ein Netzwerk, ist es das Ziel, eine exakte Kopie eines Objektes zu erstellen. Dazu muss der innere Zustand des Objektes ausgelesen und an anderer Stelle wiederhergestellt werden. Das ganze sollte im Idealfall möglich sein, ohne den Zustand der Objekte durch Aufruf von Methoden oder Konstruktoren zu verändern.
Es gibt Techniken um genau das zu tun! Beispielsweise instanziiert die Java Serialization API Klassen, auch wenn diese keinen parameterlosen Konstruktor haben. Dabei passiert etwas Magie im Bereich der JVM, denn der JVM sind Aktionen möglich, die der normale Programmierer nicht ausführen kann. Doch es gibt bereits eine Bibliothek, die diese Technik nachahmt und dem Softwareentwickler bereitstellt: Objenesis.
http://objenesis.googlecode.com/svn/docs/index.html
http://code.google.com/p/objenesis/
Zu beachten ist bei der Verwendung derartiger Techniken, dass dabei inhärent das Prinzip der Kapselung verletzt wird. Das gilt auch für die Java Reflection API, mit der u. U. von außen auf die privaten Attributen eines Objektes zugegriffen werden kann. Wie anfangs beschrieben, ist die Kapselung ein wichtiges Prinzip der Softwareentwicklung ist. Dennoch gibt es Aufgaben, die den Zugriff auf den internen Zustand der Objekte erfordern. Hier wäre es interessant zu recherchieren, wie diese Techniken einem Teilprogramm zugänglich gemacht werden, während ein anderes Teilprogramm an der Ausübung dieser Techniken gehindert wird. Ein weiteres Themenfeld, das genug Stoff für einen weiteren Artikel böte.
Außerdem ist es von der Implementierung der JVM abhängig, ob eine bestimmte Instanziierungs-Technik funktioniert. Offensichtlich sind diese Techniken nicht standardisiert. Um Objenesis auf verschiedenen JVM Implementierungen nutzen zu können, verfügt Objenesis verfügt über mehrere Instanziirungs-Techniken. Mit einem kleinen Testprogramm lässt sich in kurzer Zeit sicherstellen, ob Objenesis auf einer bestimmten JVM funktioniert.
Dennoch sollte gut überlegt werden, on man diese Techniken überhaupt einsetzt. Zum einen ,weil diese Techniken eben nicht standardisiert sind, zum anderen, weil sich damit die Kapselung umgehen lässt und damit sogar Sicherheitsprobleme auftreten könnten.
Schreiben Sie einen Kommentar