Delphi 通用工厂循环
我正试图找出如何在XE2中编写通用工厂。假设我有:Delphi 通用工厂循环,delphi,generics,delphi-xe2,factory-pattern,Delphi,Generics,Delphi Xe2,Factory Pattern,我正试图找出如何在XE2中编写通用工厂。假设我有: type TObjectTypes = (otLogger, otEmail); type TLoggerTypes = (lFile, lConsole, lDatabase); type TEmailTypes = (etPOP3, etSMTP); 课程: TSMTPEmail = class(TInterfacedObject, IEmail); // Supports emailing only TPOP3Email
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
等等
现在我这样做是为了循环所有TobjectType:
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;
过程TForm1.FormCreate(发送方:TObject);
变量
_界面;
_配置:t字典;
_ObjectType:TObjectTypes;
开始
_配置:=nil;
_配置:=TDictionary.Create;
尝试
_添加('FileLogFileName','20160320.Log');
_Add('SMTPEmailHost','mail.server.lt');
_添加('POP3Server','some_server');
对于_ObjectType:=低(TObjectTypes)到高(TObjectTypes)do
开始
_Interf:=t工厂制造(\u对象类型,\u配置);
如果已分配(_Interf),则
开始
OutputDebugString(PWideChar((_interfas TObject.ClassName));
如果支持(_Interf,IEmail),则
(_interfas IEmail).Send('X');
如果支持(_Interf,ILogger),则
(_interfas ILogger).GetLastErrorMsg;
结束;
结束;
最后
FreeAndNil(_配置);
结束;
结束;
因此,我需要一个通用工厂,并能够通过所有TLoggerTypes或所有TEmailTypes循环,而不是通过所有TObjectTypes循环,并跳过从TLoggerTypes创建一些数据库或从TEmailTypes创建etPOP3
工厂应该生产所有类型的类。在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;
现在声明可能的子类数组:
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;
最后,t工厂.Make(\u对象类型,\u配置)问题中的代码>可以替换为:
MyFactory[_ObjectType].FactoryCreate(_Configuration);
您将获得所需的对象作为MyFactoryObject类型的实例
有关更多信息,请参见。在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;
现在声明可能的子类数组:
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;
最后,t工厂.Make(\u对象类型,\u配置)问题中的代码>可以替换为:
MyFactory[_ObjectType].FactoryCreate(_Configuration);
您将获得所需的对象作为MyFactoryObject类型的实例
有关更多信息,请参阅。我根本不理解这个问题我根本不理解为什么要将构造函数命名为FactoryCreate而不是普通的旧Create?@RobKennedy我担心它会与通常的TComponent.Create(AOOwner)冲突,如果OP从TComponent继承它,这是很可能的。也许很难找到,因为它编译得很好,而且不是每个人都注意到警告“构造函数创建隐藏了基类型TComponent的虚拟方法”,我最终会有几个不同的工厂。我什么都想要一个。@EdijsKolesnikovičs是不同的日志和电子邮件对象,或者一个对象可以同时支持日志和电子邮件?再加上你的问题,你的工厂应该生产什么样的产品?如何将如此不同的对象以不同的方式处理成一个循环?通过这里演示的技术,Edijs,来自假设的单片工厂的所有特定于类的代码都转移到它所属的各个类中。“泛型工厂”剩下的唯一动作是决定实例化哪个特定类,Yuriy展示了如何通过简单的数组查找实现这一点。Delphi类本质上是类工厂。为什么要将构造函数命名为FactoryCreate而不是普通的旧Create?@RobKennedy我担心它会与通常的TComponent.Create(AOOwner)冲突,如果OP从TComponent继承它,这是很有可能的。也许很难找到,因为它编译得很好,而且不是每个人都注意到警告“构造函数创建隐藏了基类型TComponent的虚拟方法”,我最终会有几个不同的工厂。我什么都想要一个。@EdijsKolesnikovičs是不同的日志和电子邮件对象,或者一个对象可以同时支持日志和电子邮件?再加上你的问题,你的工厂应该生产什么样的产品?如何将如此不同的对象以不同的方式处理成一个循环?通过这里演示的技术,Edijs,来自假设的单片工厂的所有特定于类的代码都转移到它所属的各个类中。“泛型工厂”剩下的唯一动作是决定实例化哪个特定类,Yuriy展示了如何通过简单的数组查找实现这一点。Delphi类本质上是类工厂。