2016-03-20 2 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 и пропустить создание некоторых, например, lDatabase из TLoggerTypes или etPOP3 из TEmailTypes.

Завод должен производить все виды классов.

+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, что вполне возможно. Может быть, трудно найти, потому что он компилирует все правильно, и не все обращают внимание на предупреждение «Конструктор Create hides virtual method of base type TComponent» –

+0

В итоге у меня будет несколько разных фабрик. Я хочу за все. –

Смежные вопросы