Ein Minimalbeispiel (die "Factory" hier ist sehr simpel und unflexibel, soll aber auch nur das Prinzip verdeutlichen). Nehmen wir folgendes sehr simple Interface:
Delphi-Quellcode:
unit TierIntf;
interface
type
ITier =
interface
['
{443BCADC-CD02-4A2A-BB55-A9AEBE03D37D}']
procedure GibLaut;
end;
implementation
end.
Jetzt bauen wir uns 2 Klassen, die das Interface implementieren (der Einfachheit halber in derselben
Unit):
Delphi-Quellcode:
unit TierClasses;
interface
uses
Dialogs, TierIntf;
type
THund =
class(TInterfacedObject, ITier)
public
procedure GibLaut;
end;
TKatze =
class(TInterfacedObject, ITier)
public
procedure GibLaut;
end;
implementation
{ THund }
procedure THund.GibLaut;
begin
ShowMessage('
Wuff');
end;
{ TKatze }
procedure TKatze.GibLaut;
begin
ShowMessage('
Miau');
end;
end.
Nun eine Klassenfabrik (einen Singleton), die uns je nach Bedingung die eine oder andere Klasse instanziert.
Delphi-Quellcode:
unit TierFactory;
interface
uses
TierIntf, TierClasses;
type
TTierFactory =
class abstract
public
class function GetTier(IstHund: Boolean): ITier;
static;
end;
implementation
{ TTierFactory }
class function TTierFactory.GetTier(IstHund: Boolean): ITier;
begin
if IstHund
then
Result := THund.Create
else
Result := TKatze.Create;
end;
end.
Das Frontend muss dann letztendlich nur noch das Interface und die Fabrik kennen.
Delphi-Quellcode:
procedure TFormTest.ButtonTierClick(Sender: TObject);
var
Tier: ITier;
begin
Tier := TTierFactory.GetTier(cbHund.Checked);
Tier.GibLaut;
end;
Um wirklich flexibel zu werden, wäre die Bedingung aber kein Boolean, sondern ein Datentyp mit nahezu unendlich vielen möglichen Werten, z.B. ein String. Die Factory würde dann mindestens über 2 Klassenmethoden verfügen: Registrierung einer Klasse mit einem der möglichen Werte und Rückgabe einer Instanz anhand eines registrierten Wertes (oder auch nil, wenn kein registrierter Wert vorhanden). Um das Programm um weitere Tiere zu erweitern müssten sich deren Klassen lediglich an der Factory registrieren, an der Factory selbst und erst recht am Frontend sind keine Änderungen nötig.
[edit] Nachtrag: Bei der zuletzt angegebenen Vorgehensweise entfällt dann auch die Notwendigkeit, die Klassenunits in die uses-Klausel der Factory aufnehmen zu müssen. Allerdings ist das Instanzieren der entsprechenden Klasse dann nicht ganz trivial, ich habe das damals mit einer Menge
RTTI realisieren müssen. [/edit]