Hallo zusammen,
sorry für das lange Posting.... Und gleich der Hinweis: Ich stecke noch in Delphi 7 fest - ich denke mit Generics wäre das einfach zu lösen..
ich versuch eine AbstractFactory zu implementieren, scheitere jedoch an den Details...
Ausgangslage:
Ich habe div. unterschiedliche PDF-Formulare zu füllen, als Beispiel:
* Bestellformular Firma A
* Bestellformular Firma B
* Reklamationsformular Firma C
jedes dieser Formulare liegt zudem in einer bestimmten Version vor, die ab einem bestimmten Datum eingesetzt werden muss, Beispiel:
Bestellformular Firma A
* Version 1 gültig ab 1.1.2014
* Version 2 gültig ab 1.8.2014
....
Bislang steckt der Code dafür in einer Klasse (je Formular) drin, die dann je nach Version unterschiedlichen Code ausführt, Beispiel:
Bestellformular Firma A
Delphi-Quellcode:
...
if DruckDatum >= 1.8.2014 then
begin
....
end else if Druckdatum >= 1.1.2014 then
begin
...
end
..
Das schreit ja quasi nach dem Factory-Pattern. Also mal flugs umgesetzt. Damit das auch schön wird, gleich mit Interfaces gebastelt:
Delphi-Quellcode:
IFiller = Interface
['{7F30E379-DC1F-433B-9C56-B79D5BDEC356}']
procedure FillPDF;
end;
TFillerClass = class of TPDFFiller;
TPDFFiller = class(TInterfacedObject, IFiller)
public
procedure FillPDF; virtual; abstract;
end;
TBestellformularFirmaA = class(TPDFFiller)
public
end;
TBestellformularFirmaA_201401 = class(TBestellformularFirmaA)
public
procedure FillPDF; override;
end;
TBestellformularFirmaA_201408 = class(TBestellformularFirmaA)
public
procedure FillPDF; override;
end;
TFillerFactory = class(TObject)
....
public
procedure RegisterFiller(AClass: TFillerClass; AValidSince, AValidUntil: TDateTime);
function GetFiller(AFiller: TFillerClass; ADate: TDateTime): IFiller;
end;
Bei der Factory kann ich dann konkrete Implementierungen hinterlegen und dann in Abhängigkeit von einem Datum anfordern:
Delphi-Quellcode:
FFactory.RegisterFiller(TBestellformularFirmaA_201401, StrToDate('1.1.2014'), StrToDate('31.7.2014'));
FFactory.RegisterFiller(TBestellformularFirmaA_201408, StrToDate('1.8.2014'), StrToDate('31.12.2099'));
...
Filler := FFactory.GetFiller(TBestellformularFirmaA, now);
So weit sind im Grunde auch alle Beispiele die ich zu dem Thema bisher gefunden habe
Mein Problem: Wie bekomme ich jetzt Daten in den "Filler"?
Lösung 1:
in die Basisklasse TBestellformularFirmaA kommen alle notwendigen Felder. Der Rückgabewert bleibt jedoch ein IPDFFiller, ein direkter Cast geht in Delphi 7 noch nicht. Hier müsste ich dann eine Funktion einbauen, die mir die Instanz der konkreten Implementierung zurück gibt, und dann nach der Abfrage einen Cast machen:
Delphi-Quellcode:
var PDF: TBestellformularFirmaA;
Filler := FFactory.GetFiller(TBestellformularFirmaA, now);
PDF := TBestellformularFirmaA(Filler.GetInstance);
"fühlt" sich aber irgend wie nicht so richtig an...
Lösung 2:
man könnte natürlich argumentieren, dass der PDFFiller eigentlich nichts mit den Nutzdaten zu tun haben sollte, d.h. dass es hier eine Datenhaltungsklasse geben müsste, die Datenfelder also nicht in TBestellformularFirmaA definieren sondern z.B. in TBestellformularFirmaA_Data - nur dann müsste ich im PDFFiller wieder eine Möglichkeit haben bel. Daten zu übergeben, dazu fällt mir aber auch wieder nur ein Typecast ein:
Delphi-Quellcode:
IFiller = Interface
['{7F30E379-DC1F-433B-9C56-B79D5BDEC356}']
procedure FillPDF(IData: Interface);
end;
um das dann wieder in der konkreten Implementierung zu casten. Sieht mir aber auch nicht "richtig" aus.
Lösung 3: Für jedes Formular eine eigene Factory bauen - das wäre mit Generics nach meinem Empfinden recht einfach zu realisieren, in Delphi7 aber mit deutlich mehr Code und dem Aufwand in jeder Factory dann wieder casten zu müssen
Und jetzt meine Fragen:
* gibt es noch ALternativen bzw. was mich eigentlich bewegt: Was habe ich am Factory-Pattern nicht verstanden?
Grüße