2016-03-20 71 views
0

我想弄清楚如何在XE2中編寫一個通用工廠。比方說,我有這樣的:通用工廠循環

type 
    TObjectTypes = (otLogger, otEmail); 

type 
    TLoggerTypes = (lFile, lConsole, lDatabase); 

type 
    TEmailTypes = (etPOP3, etSMTP); 

類:

TSMTPEmail = class(TInterfacedObject, IEmail); // Supports emailing only 
TPOP3Email = class(TInterfacedObject, IEmail); // Supports emailing only 
TFileLogger = class(TInterfacedObject, ILogger); // Supports logging only 

現在我這樣做是爲了環通所有TObjectTypes:

procedure TForm1.FormCreate(Sender: TObject); 
var 
    _Interf: IInterface; 
    _Configuration: TDictionary<string, TValue>; 
    _ObjectType: TObjectTypes; 
begin 
    _Configuration := nil; 
    _Configuration := TDictionary<string, TValue>.Create; 
    try 
    _Configuration.Add('FileLogFileName', '20160320.Log'); 
    _Configuration.Add('SMTPEmailHost', 'mail.server.lt'); 
    _Configuration.Add('POP3Server', 'some_server'); 

    for _ObjectType := Low(TObjectTypes) to High(TObjectTypes) do 
    begin 
     _Interf := TTheFactory.Make(_ObjectType, _Configuration); 
     if Assigned(_Interf) then 
     begin 
     OutputDebugString(PWideChar((_Interf as TObject).ClassName)); 
     if Supports(_Interf, IEmail) then 
      (_Interf as IEmail).Send('X'); 

     if Supports(_Interf, ILogger) then 
      (_Interf as ILogger).GetLastErrorMsg; 
     end; 
    end; 
    finally 
    FreeAndNil(_Configuration); 
    end; 
end; 

所以,我需要一個通用工廠,並能夠循環不通過所有的TObjectTypes,但通過所有TLoggerTypes或通過所有TEmailTypes並跳過創建一些例如l來自TLoggerTypes的數據庫或來自TEmailTypes的etPOP3。

工廠應該生產各種類。

+1

我根本不明白這個問題 –

回答

4

在Delphi中製作工廠是非常簡單的,這要歸功於元類(類引用),簡單的其中的例子是TClass

TClass = class of TObject 

在大多數情況下,你應該定義自己的抽象類工廠所有成員元類吧:

TMyFactoryObject = class (TObject) 
    public 
    constructor FactoryCreate(aConfiguration: TConfiguration); virtual; abstract; 
end; 

TMyFactoryClass = class of TMyFactoryObject; 

在這種抽象類,你可以添加一些常見的所有後代的方法,在我的例子中,我們構造這需要配置參數。如何對它做出反應將決定在後代。

然後你聲明子類:

TMyLogger = class (TMyFactoryObject, ILogger) 
    private 
    ... 
    public 
    constructor FactoryCreate(aConfiguration: TConfiguration); override; 
    ... //implementation of ILogger interface etc 
    end; 

TMyEmail = class (TMyFactoryObject, IEmail) 
    private 
    ... 
    public 
    constructor FactoryCreate(aConfiguration: TConfiguration); override; 
    ... //implementation of IEmail interface etc 
    end; 

現在你聲明的可能派生類數組:

var 
    MyFactory: array [otLogger..otEmail] of TMyFactoryClass; 

,並在初始化部分或在其他地方,你填充這個數組:

MyFactory[otLogger]:=TMyLogger; 
MyFactory[orEmail]:=TMyEmail; 

最後,從您的問題TTheFactory.Make(_ObjectType, _Configuration);可以被替換與:

MyFactory[_ObjectType].FactoryCreate(_Configuration); 

並且您將獲得需要的對象作爲類型MyFactoryObject的實例。

請參閱http://docwiki.embarcadero.com/RADStudio/Seattle/en/Class_References瞭解更多信息。

+0

爲什麼要命名構造函數FactoryCreate而不是普通的Create? –

+0

@RobKennedy我擔心它會與通常的TComponent.Create(aOwner)發生衝突,如果OP從TComponent繼承它,這很有可能。也許很難找到,因爲它編譯所有權利,而不是所有人都注意警告'構造函數創建隱藏基類型TComponent的虛擬方法' –

+0

我會結束幾個不同的工廠。我想要一切。 –