Ich suche nach Mustern oder architektonischen Anleitungen für ein bevorstehendes Feature, das ich entwerfe. Grundsätzlich handelt es sich um eine Exportfunktion mit mehreren Exportzielen, und ich suche nach einer Möglichkeit, sie generisch genug zu gestalten, wenn das Einfügen neuer Exportziele nicht viele grundlegende Änderungen erfordert. Bei Exportzielen beziehe ich mich einfach auf verschiedene Arten von Ausgaben, sei es PDFs, PowerPoint-Präsentationen, Word-Dokumente, RSS usw. Ich habe einen Basisdatensatz, der in JSON und XML dargestellt wird. Diese Daten werden verwendet, um Bilder (unter Verwendung einer beliebigen Anzahl oder Exporttypen [z. B. PNG, JPG, GIF usw.), Grafiken, Textdarstellungen, Tabellen und mehr zu erstellen.
Ich versuche einen Weg zu finden, um das gesamte Rendering und Layout in eine Art Rendering- oder Layout-Engine zu abstrahieren, die das Hinzufügen weiterer Exportziele übernimmt. Jede Hilfe / Anregungen / Ressourcen, wie man dies angeht, wäre sehr dankbar. Danke im Voraus.
Für eine bildliche Darstellung dessen, was ich erreichen möchte.
quelle
Antworten:
Für mich wären Schnittstellen und eine Fabrik der richtige Weg. Eine, die Verweise auf Schnittstellen zurückgibt, hinter denen sich verschiedene Klassen verstecken können. Die Klassen, die das eigentliche Grunzen ausführen, müssen alle bei der Factory registriert sein, damit sie wissen, welche Klasse bei einer Reihe von Parametern instanziiert werden muss.
Hinweis: Anstelle von Schnittstellen können Sie auch abstrakte Basisklassen verwenden. Der Nachteil besteht jedoch darin, dass Sie für einzelne Vererbungssprachen auf eine einzelne Basisklasse beschränkt sind.
Code ist in Delphi (Pascal) -Syntax, da dies die Sprache ist, mit der ich am besten vertraut bin.
Nachdem alle implementierenden Klassen bei der Factory registriert wurden, sollten Sie in der Lage sein, einen Schnittstellenverweis auf eine Instanz einer solchen Klasse anzufordern. Zum Beispiel:
sollte einen IReader-Verweis auf eine Instanz von TXMLReader zurückgeben; eine IWriter-Referenz auf eine Instanz von TPowerPointWriter und eine IRepresentation-Referenz auf eine Instanz von THTMLTable.
Jetzt muss die Rendering-Engine nur noch alles zusammenbinden:
Die IReader-Schnittstelle sollte Methoden zum Lesen der Daten bereitstellen, die von IRepresentation-Implementierern zum Erstellen der Darstellung der Daten benötigt werden. Ebenso sollte IRepresentation Methoden bereitstellen, die IWriter-Implementierer benötigen, um die Datendarstellung in das angeforderte Exportdateiformat zu exportieren.
Unter der Annahme, dass die Daten in Ihren Dateien tabellarischer Natur sind, könnten IReader und seine unterstützenden Schnittstellen folgendermaßen aussehen:
Über einen Tisch zu iterieren wäre dann eine Frage von
Da es sich bei den Darstellungen um Bilder, Grafiken und Text handelt, verfügt die IR-Darstellung wahrscheinlich über ähnliche Methoden wie IReader zum Durchlaufen einer konstruierten Tabelle und über Methoden zum Abrufen der Bilder und Grafiken, beispielsweise als Bytestrom. Es wäre Sache der IWriter-Implementierer, die Tabellenwerte und die Bild- / Grafikbytes gemäß den Anforderungen des Exportziels zu codieren.
quelle
Ich stimme zu, dass mehr Informationen erforderlich sind, um über eine Architektur nachzudenken. Der einfachste Weg, verschiedene Arten von Objekten zu erstellen, die sich gleich verhalten (dh alle erzeugen eine Ausgabe), ist die Verwendung des Factory-Musters. Mehr Infos hier
quelle
Sie könnten mit so etwas enden.
Die beiden Fabriken basieren auf:
1 - zum Konvertieren des Eingabetyps (Json / XML) in eine konkrete Implementierung zum Konvertieren dieser Daten in ein Bild / Diagramm
2 - Eine zweite Factory zur Entscheidung, wie die Ausgabe in ein Word-Dokument / PDF-Dokument gerendert werden soll
Der Polymorphismus verwendet eine gemeinsame Schnittstelle für alle gerenderten Daten. So kann ein Bild / eine Tabelle als einfache Oberfläche verschoben werden.
1 - Factory zum Konvertieren von JSON / XML-Daten in eine konkrete Implementierung:
In der folgenden Factory können Sie die XML-Daten oder Json-Daten in den richtigen konkreten Typ konvertieren.
Die konkreten Implementierungen erledigen die ganze schwere Arbeit der Konvertierung der Daten in den entsprechenden Typ. Sie konvertieren die Daten auch in die IConvertedData-Schnittstelle, die für den Polymorphismus verwendet wird.
Sie können diese Implementierungen nach Bedarf hinzufügen, wenn Ihr Code erweitert wird.
Über die IConvertedData-Schnittstelle können Sie einen einzelnen Typ in die nächste Phase übergeben: HINWEIS: Möglicherweise geben Sie hier keine Hohlräume zurück. Dies kann ein Byte [] für Bilder oder ein OpenXml-Dokument für das WordDocument sein. Bei Bedarf anpassen.
Polymorphismus:
Dies wird verwendet, um die Daten in den entsprechenden Ausgabetyp zu konvertieren. dh das Rendern in PDF für Bilddaten kann unterschiedliche Rendering-Bilddaten für PowerPoint sein.
2 - Werkseitig das Ausgabeformat festlegen:
Jede konkrete Implementierung stellt eine allgemeine Methode bereit, die maskiert, wie der Export in die IConvertedData-Implementierungen zurückgeworfen wird
Ein Beispiel-Client für all dies wäre:
quelle
Wir haben hier ein ähnliches Problem gelöst: https://ergebnisse.zensus2011.de/?locale=de Dort haben wir meistens "Tabellen" und "Grafiken", die in verschiedenen Formaten exportiert werden sollen: pdf, excel, web. Unsere Idee war es, jedes Objekt, das gerendert werden soll, als eigene Java-Klasse mit Schnittstellen zum Erstellen und Lesen dieser Klassen anzugeben. In Ihrem Fall gibt es 2 Implementierungen für jedes Objekt zum Erstellen (xml, json) und 4 Implementierungen zum Rendern (Lesen).
Beispiel: Sie benötigen einige Klassen für Tabellen: Klassentabelle (behandelt Tabellenstruktur, Validierung und Inhalt) Schnittstelle CreateTable (enthält Tabellendaten, Zellen, Bereiche, Inhalte) Schnittstelle ReadTable (Getter für alle Daten)
Wahrscheinlich brauchen Sie nicht die Schnittstellen (oder nur eine), aber ich denke, es bietet immer eine gute Entkopplung, die besonders beim Testen nützlich ist.
quelle
Ich denke, was Sie suchen, ist das Strategiemuster . Sie haben verschiedene Klassen, um die Daten im gewünschten Format auszugeben, und wählen zur Laufzeit einfach die entsprechende aus. Das Hinzufügen eines neuen Formats sollte so einfach sein wie das Hinzufügen einer weiteren Klasse, die die erforderliche Schnittstelle implementiert. Ich habe dies in Java häufig mit Spring gemacht, um einfach eine Karte von Konvertern zu verwalten, die nach dem Formattyp sortiert ist.
Wie andere bereits erwähnt haben, wird dies normalerweise dadurch erreicht, dass alle Klassen dieselbe Schnittstelle implementieren (oder von derselben Basisklasse abstammen) und die Implementierung über eine Factory auswählen.
quelle