Dokumenten-Typen mit Metadaten

Kurz

Mittels einer Filter- und einer Factory-Methode werden unterschiedliche Objekte erzeugt, die ein gemeinsames Interface implementieren. Anlass war das Refactoring einer Software-Komponente, die Metadaten für unterschiedliche Dokumenten-Typen geschrieben hat. If-Orgien wurden entfernt.

Ausgangssituation

Es gibt sechs unterschiedliche Typen von Dokumenten. Der Einfachheit und Diskretion halber nenne ich sie hier “Typ-1″ bis “Typ-5″ und “Standard-Typ”. Jeder dieser Typen wird durch neun Werte charakterisiert, die ich unkompliziert aus Feldern der konkreten Lotus-Notes-Dokumente entnehmen kann. Die Felder nenne ich hier “Feld-1″ bis “Feld-9″. Einige Felder werden für allen Typen gebraucht, andere sind jeweils unterschiedlich, und manchmal werden keine Feldwerte ausgelesen, sondern Konstanten benutzt.

Der bestehende Code wiederholt mehrfach dieses Muster, hier in Pseudocode:

Das funktioniert zweifellos. Aber es hat zwei Nachteile.

Erstens: Wenn ich möchte, dass ein neuer nicht-Standard-Dokumenten-Typ verarbeitet werden kann, dann muss ich alle diese if-Blöcke finden und anpassen. Das ist aufwändig und fehleranfällig, weil dieser Code nicht alleine steht, sondern von anderem Code umgeben ist, der auch if-Blöcke hat.

Zweitens: Es ist nur schwerlich zu erkennen, welche Felder für welchen Typen benutzt werden. Das bremst Antworten für andere Entwickler aus, die mangels Dokumentation bei mir anklopfen. Und das macht es langwierig, Änderungen einzupflegen. Dieser Code ist so interessant wie ein fingernagelgrosses Stück Millimeter-Papier, aber leider ist er unentbehrlich.

OOAD und Pattern

Aus Sicht Objekt-Orientierter-Analyse-und-Designs liegt es nahe, den typenspezifischen Code in eigene Klassen zu kapseln, anstelle der Erbsenzählerei in den if-Blöcken. Also schaffe ich in Java ein Interface >>DocType<< mit der Methode “String getFeldwert ( int feldx )“. Die sechs Dokumenten-Typen stelle ich als Klassen “Typ-1-DocType” usw. dar, die dieses Interface implementieren.

Wie komme ich an ein jeweils passendes Objekt? Ich erschaffe einen DocTypeCreator. Der erzeugt für ein gegebenes Notes-Dokument ein passendes Objekt. Mit langem if-Block wie oben?

Nein, eleganter: Der DocTypeCreator hat eine Liste von DocType-Objekten, eins für jede implementierende Klasse des Interfaces >>DocType<<. Das Interface erweitere ich um zwei Methoden. Erstens um die Filter-Methode “boolean acceptDoc ( NotesDocument doc )“. So kann jede implementierende Klasse Auskunft darüber geben, ob sie für das fragliche Dokument zuständig ist. Zweitens um die Factory-Methode “DocType createDocType ( NotesDocument doc )“. So erzeugt ein DocType-Objekt ein weiteres DocType-Objekt seiner eigenen Klasse, das das gegebene Notes-Dokument als Datenquelle nutzt. Der DocType-Creator iteriert über die Liste seiner DocType-Objekte. Es braucht genau eine if-Abfrage: Wenn das aktuelle Objekt in der Iteration das Notes-Dokument akzeptiert, dann lasse es ein neues Objekt seiner Klasse mit eben diesem Notes-Dokument erzeugen.

Kröte

Diese Implementierung hat meines Erachtens nur einen Nachteil: Jede implementierende DocType-Klasse braucht einen parameterlosen Konstruktor, damit der DocTypeCreator an Objekte der unterschiedlichen Klassen kommen kann. Ein DocType-Objekt, das mit einem parameterlosen Konstruktor erzeugt wurde, kann nur dazu benutzt werden, um weitere gleichklassige DocType-Objekte zu erzeugen. Es hat aber kein Notes-Dokument als Datenquelle. So besteht die Gefahr, dass ein DocType-Objekt falsch verwendet wird. Dieser Gefahr begegne ich mit aussagekräftiger Dokumentation.

Vanille

Jeder DocType gibt nun übersichtlich Auskunft darüber, welche Feldwerte er liefert. Und um einen neuen Typen zu verarbeiten, braucht es nur zwei gefahrlose Schritte: Die Implementierung einer entsprechenden Klasse nach Muster >>DocType<< und das Erweitern der Liste im DocTypeCreator. Alle anderen Stellen bleiben unangetastet. Die Liste im DocTypeCreator könnte auch mittel Java-Reflections erzeugt werden.

Dieser Beitrag wurde unter Allgemein veröffentlicht. Setze ein Lesezeichen auf den Permalink.