Generic factory looping

℡╲_俬逩灬. 提交于 2019-12-12 05:13:51

问题


I am trying to figure out how to write a generic factory in XE2. Lets say I have this:

type
  TObjectTypes = (otLogger, otEmail);

type
  TLoggerTypes = (lFile, lConsole, lDatabase);

type
  TEmailTypes = (etPOP3, etSMTP);

Classes:

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

etc.

Now I do this to loop thru all 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;

So, I need a generic factory and be able to loop not thru all TObjectTypes, but thru all TLoggerTypes or thru all TEmailTypes and skip creating some e.g. lDatabase from TLoggerTypes or etPOP3 from TEmailTypes.

Factory should produce all kind of classes.


回答1:


In Delphi making factories is pretty simple, thanks to metaclasses (class references), simple example of which is TClass:

TClass = class of TObject

In most cases, you should define your own abstract class for all factory members and metaclass for it:

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

TMyFactoryClass = class of TMyFactoryObject;

In this abstract class you can add some methods common for all descendants, in my example we have constructor which takes configuration as argument. How to react to it will be determined in descendants.

Then you declare descendant classes:

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;

now you declare array of possible descendant classes:

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

and in initialization section or in other places you populate this array:

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

At last, TTheFactory.Make(_ObjectType, _Configuration); from your question can be replaced with:

MyFactory[_ObjectType].FactoryCreate(_Configuration);

and you'll get needed object as instance of type MyFactoryObject.

See http://docwiki.embarcadero.com/RADStudio/Seattle/en/Class_References for more information.



来源:https://stackoverflow.com/questions/36111172/generic-factory-looping

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!