Fre*_*red 2 delphi generics factory delphi-2009
假设我有一个TModel:
TModelClass = class of TModel;
TModel = class
procedure DoSomeStuff;
end;
Run Code Online (Sandbox Code Playgroud)
和2个后代:
TModel_A = class(TModel);
TModel_B = class(TModel);
Run Code Online (Sandbox Code Playgroud)
和工厂:
TModelFactory = class
class function CreateModel_A: TModel_A;
class function CreateModel_B: TModel_B;
end;
Run Code Online (Sandbox Code Playgroud)
现在我想重构一下:
TModelFactory = class
class function CreateGenericModel(Model: TModelClass) : TModel
end;
class function TModelFactory.CreateGenericModel(Model: TModelClass) : TModel
begin
...
case Model of
TModel_A: Result := TModel_A.Create;
TModel_B: Result := TModel_B.Create;
end;
...
end;
Run Code Online (Sandbox Code Playgroud)
到目前为止没关系,但每次创建TModel后代时,我都要修改工厂case语句.
我的问题:这可能为我的所有TModel后代创建一个100%的通用工厂,所以每次创建TModel后代我都不需要修改TModelFactory吗?
我尝试使用Delphi 2009泛型,但没有找到有价值的信息,所有都与基本用法TList<T>等有关.
更新 对不起,但也许我不清楚或不理解你的答案(我还是一个菜鸟),但我想要实现的是:
var
M: TModel_A;
begin
M: TModelFactory.CreateGenericModel(MY_CONCRETE_CLASS);
Run Code Online (Sandbox Code Playgroud)
好吧,你可以写
class function TModelFactory.CreateGenericModel(AModelClass: TModelClass): TModel;
begin
Result := AModelClass.Create;
end;
Run Code Online (Sandbox Code Playgroud)
但是你不再需要工厂了.通常会有一个不同类型的选择器,如整数或字符串ID,以选择工厂应创建的具体类.
编辑:
要回答你关于如何在不需要更改工厂的情况下添加新类的注释 - 我将为您提供一些适用于非常旧的Delphi版本的简单示例代码,Delphi 2009应该采用更好的方法来实现这一点.
每个新的后代类只需要在工厂注册.可以使用多个ID注册相同的类.代码使用字符串ID,但整数或GUID也可以使用.
type
TModelFactory = class
public
class function CreateModelFromID(const AID: string): TModel;
class function FindModelClassForId(const AID: string): TModelClass;
class function GetModelClassID(AModelClass: TModelClass): string;
class procedure RegisterModelClass(const AID: string;
AModelClass: TModelClass);
end;
{ TModelFactory }
type
TModelClassRegistration = record
ID: string;
ModelClass: TModelClass;
end;
var
RegisteredModelClasses: array of TModelClassRegistration;
class function TModelFactory.CreateModelFromID(const AID: string): TModel;
var
ModelClass: TModelClass;
begin
ModelClass := FindModelClassForId(AID);
if ModelClass <> nil then
Result := ModelClass.Create
else
Result := nil;
end;
class function TModelFactory.FindModelClassForId(
const AID: string): TModelClass;
var
i, Len: integer;
begin
Result := nil;
Len := Length(RegisteredModelClasses);
for i := 0 to Len - 1 do
if RegisteredModelClasses[i].ID = AID then begin
Result := RegisteredModelClasses[i].ModelClass;
break;
end;
end;
class function TModelFactory.GetModelClassID(AModelClass: TModelClass): string;
var
i, Len: integer;
begin
Result := '';
Len := Length(RegisteredModelClasses);
for i := 0 to Len - 1 do
if RegisteredModelClasses[i].ModelClass = AModelClass then begin
Result := RegisteredModelClasses[i].ID;
break;
end;
end;
class procedure TModelFactory.RegisterModelClass(const AID: string;
AModelClass: TModelClass);
var
i, Len: integer;
begin
Assert(AModelClass <> nil);
Len := Length(RegisteredModelClasses);
for i := 0 to Len - 1 do
if (RegisteredModelClasses[i].ID = AID)
and (RegisteredModelClasses[i].ModelClass = AModelClass)
then begin
Assert(FALSE);
exit;
end;
SetLength(RegisteredModelClasses, Len + 1);
RegisteredModelClasses[Len].ID := AID;
RegisteredModelClasses[Len].ModelClass := AModelClass;
end;
Run Code Online (Sandbox Code Playgroud)
如果构造函数是虚拟的,则Model.Create的解决方案有效.
如果你使用delphi 2009,你可以使用泛型使用另一个技巧:
type
TMyContainer<T: TModel, constructor> (...)
protected
function CreateModel: TModel;
end;
function TMyContainer<T>.CreateModel: TModel;
begin
Result := T.Create; // Works only with a constructor constraint.
end;
Run Code Online (Sandbox Code Playgroud)