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.
TRepresentationType = (rtImage, rtTable, rtGraph, ...);
Factory.RegisterReader(TJSONReader, 'json');
Factory.RegisterReader(TXMLReader, 'xml');
Factory.RegisterWriter(TPDFWriter, 'pdf');
Factory.RegisterWriter(TPowerPointWriter, 'ppt');
Factory.RegisterWriter(TWordWriter, 'doc');
Factory.RegisterWriter(TWordWriter, 'docx');
Factory.RegisterRepresentation(TPNGImage, rtImage, 'png');
Factory.RegisterRepresentation(TGIFImage, rtImage, 'gif');
Factory.RegisterRepresentation(TJPGImage, rtImage, 'jpg');
Factory.RegisterRepresentation(TCsvTable, rtTable, 'csv');
Factory.RegisterRepresentation(THTMLTable, rtTable, 'html');
Factory.RegisterRepresentation(TBarChart, rtTGraph, 'bar');
Factory.RegisterRepresentation(TPieChart, rtTGraph, 'pie');
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:
Factory.GetReader('SomeFileName.xml');
Factory.GetWriter('SomeExportFileName.ppt');
Factory.GetRepresentation(rtTable, 'html');
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:
procedure Render(
aDataFile: string;
aExportFile: string;
aRepresentationType: TRepresentationType;
aFormat: string;
);
var
Reader: IReader;
Writer: IWriter;
Representation: IRepresentation;
begin
Reader := Factory.GetReaderFor(aDataFile);
Writer := Factory.GetWriterFor(aExportFile);
Representation := Factory.GetRepresentationFor(aRepresentationType, aFormat);
Representation.ConstructFrom(Reader);
Writer.SaveToFile(Representation);
end;
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:
IReader = interface(IInterface)
function MoveNext: Boolean;
function GetCurrent: IRow;
end;
IRow = interface(IInterface)
function MoveNext: Boolean;
function GetCurrent: ICol;
end;
ICol = interface(IInterface)
function GetName: string;
function GetValue: Variant;
end;
Über einen Tisch zu iterieren wäre dann eine Frage von
while Reader.MoveNext do
begin
Row := Reader.GetCurrent;
while Row.MoveNext do
begin
Col := Row.GetCurrent;
// Do something with the column's name or value
end;
end;
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.