我有各种类实例的列表。我需要能够在不知道要创建什么的情况下创建类的新实例。所涉及的所有对象都具有相同的祖先。实际复制对象的成员变量很容易......这是我遇到问题的新对象的创建。
诚然,我可以这样做:
case MyObjectTypeInstance.MyTypeEnum of
obj1:
Result:=TObjectType1.Create;
obj2:
Result:=TObjectType2.Create;
obj3:
Result:=TObjectType3.Create;
end;
不符合“开放/封闭原则”。
最初我以为我可以做类似“结果:= MyObjectTypeInstance.Create;”的事情。但由于破坏者的困难,这并不像预期的那样有效。
这是最新猜测我应该怎么做......
var
fooA, fooB:TFoo;
begin
fooA:=TFoo2.Create; // it could be any of many types
fooB:=? // how to create fooB of same class type as fooA????
// do something
fooA.Free;
fooB.Free;
end;
我会认为这会更容易!
谢谢你的帮助!
答案 0 :(得分:11)
如果所有类都有共同的祖先,你可以这样做:
type
TAncestor = class;
TAncestorClass = class of TAncestor;
TAncestor = class
public
constructor Create; virtual;
class function CreateClass(const AId: string): TAncestor;
class procedure RegisterClass(const AId: string; const AType: TAncestorClass);
end;
class function TAncestor.CreateClass(const AId: string): TAncestor;
var
atype : TAncestorClass;
begin
atype := GetAncestorClass(AId);
if atype<>nil then
Result := atype.Create
else
Result := nil;
end;
class procedure TAncestor.RegisterClass(const AId: string;
const AType: TAncestorClass);
begin
SetAncestorClass(AId, AType); // Link id to class type
end;
您可以使用任何类型的标识进行类型注册。只要它们是独一无二的。
答案 1 :(得分:8)
选项1 - 创建名称/类映射列表:Is there a way to instantiate a class by its name in delphi?
选项2 - 使用'of class'变量。
type
TBaseObj = class
end;
TObjA = class(TBaseObj)
end;
TBaseObjClass = class of TBaseObj;
var
objCls: TBaseObjClass;
obj: TBaseObj;
objCls := TObjA;
obj := objCls.Create;
//obj is of type TObjA
答案 2 :(得分:4)
您可能想要创建一个Abstract Factory或Factory Method类。这些是常见的Design Patterns,经过测试,经过验证的开发范例。
答案 3 :(得分:2)
谢谢大家的答案!
dar7yl的解决方案完全符合我的需求。
type
TFoo = class
private
{ private declarations }
public
{ public declarations }
class function MakeAnother:TFoo;
end;
TFoo1 = class(TFoo)
private
{ private declarations }
public
{ public declarations }
end;
TFoo2 = class(TFoo)
private
{ private declarations }
public
{ public declarations }
end;
var
fooA, fooB:TFoo;
begin
fooA:=TFoo2.Create;
foob:=fooA.MakeAnother;
// do something here
fooA.Free;
fooB.Free;
end;
{ TFoo }
class function TFoo.MakeAnother: TFoo;
begin
Result:=Create;
end;
答案 4 :(得分:2)
另一个更混乱的版本是使用“class of type”和TObject.ClassType
type
TFoo = class
private
{ private declarations }
public
{ public declarations }
constructor Create(WhatEver : Integer);virtual;// just to show need for params
end;
TFooClass = class of TFoo;
TFoo1 = class(TFoo)
private
{ private declarations }
public
{ public declarations }
constructor Create(WhatEver : Integer);override;// just to show need for params
end;
TFoo2 = class(TFoo)
private
{ private declarations }
public
{ public declarations }
end;
{$R *.dfm}
procedure TForm10.Button1Click(Sender: TObject);
var
fooA, fooB:TFoo;
begin
fooA:=TFoo2.Create(0);
fooB:= TFooClass(FooA.ClassType).Create(1);
// do something here
fooA.Free;
fooB.Free;
end;
{ TFoo }
constructor TFoo.Create(WhatEver: Integer);
begin
ShowMessageFmt('%s %d', [Self.ClassName, WhatEver]);
end;
{ TFoo1 }
constructor TFoo1.Create(WhatEver: Integer);
begin
inherited;
end;