2016-03-20 13 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をループすることができます。 TLoggerTypesのlDatabaseまたはTEmailTypesのetPOP3。

工場はあらゆる種類のクラスを生成する必要があります。工場を作り、Delphiで

+1

私は全くの質問を理解していません –

答えて

4

は、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

普通の古いCreateではなく、FactoryCreateという名前のコンストラクタを作成するのはなぜですか? –

+0

@RobKennedy OPがTComponentから継承している場合は、通常のTComponent.Create(aOwner)と矛盾してしまうのではないかと恐れていました。すべての人が警告を出すわけではないので、見つけにくいかもしれません。コンストラクタ基本型TComponentの仮想メソッドを作成しないでください。 –

+0

私はいくつかの異なる工場で終了します。私はすべてを一つにしたい。 –