Ich arbeite an einem Produkt, für das eines der Module die Aufgabe hat, XML-Dateien zu analysieren und den erforderlichen Inhalt in einer Datenbank abzulegen. Obwohl die gegenwärtige Anforderung nur darin besteht, XML-Dateien zu analysieren, möchte ich mein Parsing-Modul so gestalten, dass ich in Zukunft alle Arten von Dateien unterstützen kann. Der Grund für diesen Ansatz ist, dass wir dieses Produkt für einen bestimmten Kunden entwickeln, es aber in naher Zukunft an andere Kunden verkaufen möchten. Alle Systeme im Ökosystem für den aktuellen Client produzieren und konsumieren XML-Dateien. Dies ist jedoch möglicherweise bei anderen Clients nicht der Fall.
Was habe ich bisher versucht? (Die Gegenwart) Ich habe das folgende Design im Auge, das auf dem Strategiemuster basiert. Ich habe den Code in Eclipse schnell aufgeschrieben, um mein Design zu vermitteln. Daher wäre es großartig, wenn andere Aspekte wie die richtige Behandlung von Ausnahmen vorerst ignoriert würden.
Parser: Die Strategieschnittstelle, die eine Analysemethode verfügbar macht.
public interface Parser<T> {
public T parse(String inputFile);
}
* Der Grund für die Verwendung eines generischen Parameters besteht darin, jeden Rückgabetyp zuzulassen und die Typensicherheit bei der Kompilierung zu gewährleisten.
ProductDataXmlParser Eine konkrete Klasse zum Parsen einer product.xml-Datei, die produktbezogene Informationen enthält. (mit XMLBeans)
public class ProductDataXmlParser implements Parser<ProductDataTYPE> {
public ProductDataTYPE parse(String inputFile) {
ProductDataTYPE productDataDoc = null;
File inputXMLFile = new File(inputFile);
try {
productDataDoc = ProductDataDocument.Factory.parse(inputXMLFile);
} catch(XmlException e) {
System.out.println("XmlException while parsing file : "+inputXMLFile);
} catch(IOException e) {
System.out.println("IOException while parsing file : "+inputXMLFile);
}
return productDataDoc.getProductData();
}
}
Dabei gilt Folgendes: ProductDataTYPE und ProductDataDocument sind XMlBean-POJO-Klassen, die mit xsd und dem Befehl scomp generiert wurden.
Die Zukunft
Wenn ich eine product.txt-Datei habe, die in Zukunft analysiert werden soll, kann ich mein eigenes POJO mit dem Namen ProductData definieren, das den erforderlichen Inhalt der Datei enthält. Ich kann dann eine konkrete Klasse mit dem Namen ProductDataFlatFileParser erstellen, die die Parser-Schnittstelle implementiert, und die Analysemethode das POJO ProductData für mich füllen lassen, nachdem die Datei analysiert wurde.
Ist dieser Entwurf sinnvoll? Gibt es offensichtliche Mängel in diesem Design? Nach dem derzeitigen Stand des Designs gestatte ich den konkreten Klassen, den Algorithmus zum Parsen einer Datei zu definieren und der konkreten Klasse zu überlassen, wo die Daten gefüllt werden sollen. Das Design scheint eher von den Domänenobjekten als von den Dateiformaten abhängig zu sein. Ist das eine schlechte Sache? Alle Beiträge zur Verbesserung meines Designs werden sehr geschätzt.
Antworten:
Ich habe ein paar Bedenken:
Parser<T>
im Grunde genommen gut ist. Ich sehe zwei potenzielle Probleme: (1) Es wird eine Dateieingabe vorausgesetzt. Was passiert, wenn Sie versuchen, einen JSON-Stream zu analysieren, den Sie beispielsweise aus einer HTTP-Antwort abgerufen haben? und (2) es liefert nicht unbedingt viel Wert, außer als Teil eines größeren generischen Frameworks, in dem Sie viele verschiedene Arten von Parsern für viele verschiedene Arten von Daten haben. Aber ich bin nicht davon überzeugt, dass Sie solch einen großen allgemeinen Rahmen brauchen. Sie haben gerade einen sehr einfachen, konkreten Anwendungsfall, soweit ich das beurteilen kann: Analysieren Sie eine XML-Datei in eine Liste vonProductData
s.ProductDataXmlParser
. Ich würde esRuntimeException
stattdessen in eine Art umwandeln .quelle
Ihr Design ist nicht die beste Option. Nach Ihrem Entwurf die einzige Möglichkeit, es zu verwenden:
Wir können nicht sehen, dass das obige Beispiel zu viel bringt. Wir können so etwas nicht machen:
Sie können die folgenden zwei Optionen in Betracht ziehen, bevor Sie das Generikum suchen:
Unabhängig davon, woher die Datenquelle stammt, haben die Produktdaten dasselbe Format, bevor Sie sie in der Datenbank speichern. Es ist der Vertrag zwischen dem Kunden und Ihrem Dump-Service. Ich gehe also davon aus, dass Sie die gleichen ProductData als Ausgabe haben. Sie können einfach eine Schnittstelle definieren:
Darüber hinaus definieren Sie ProductData als Schnittstelle, wenn Sie es flexibler wollen.
Wenn Sie nicht möchten, dass der Parser mit den Daten gemischt wird. Sie können es in zwei Schnittstellen aufteilen:
Und Ihr Parser wird so aussehen:
Wenn die ProductData nicht ähnlich sind und Sie die Parser-Schnittstelle wiederverwenden möchten. Du kannst es so machen:
quelle
Für den Fall, dass Sie lieber etwas verwenden möchten, das bereits verfügbar ist, habe ich eine Java-Bibliothek namens JRecordBind erstellt , die auf XMLSchema basiert (unterstützt von JAXB).
Es wurde entwickelt, um Dateien mit fester Länge zu konsumieren / zu produzieren. Da XMLSchema deren Struktur definiert, können Sie es mit JAXB verwenden, um XML-Dateien zu marshallen / zu unmarshallen
quelle