问题
i have a list of class instances of various kinds. i need to be able to create a new instance of a class without knowing for sure what to create. all the objects involved have the same ancestor. the actual copying of the object's member variables is easy...it's the creation of the new object where i have a problem.
admittedly i could do something like this:
case MyObjectTypeInstance.MyTypeEnum of
obj1:
Result:=TObjectType1.Create;
obj2:
Result:=TObjectType2.Create;
obj3:
Result:=TObjectType3.Create;
end;
that wouldn't follow the "open/closed principle".
initially i thought i could do something like "Result:=MyObjectTypeInstance.Create;" but that didn't work as hoped because of destructor difficulties.
here's the latest guess how i should be doing this...
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;
i would've thought this'd be easier!
thank you for your help!
回答1:
You will probably want to create an Abstract Factory or Factory Method class. These are common Design Patterns which are tested, proven development paradigms.
回答2:
If all classes have a common ancestor, you can do something like this:
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;
You can use any kind of identification for the type registration. As long as they are unique.
回答3:
Option 1 - create a list of name/class mappings: Is there a way to instantiate a class by its name in delphi?
Option 2 - use a 'of class' variable.
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
回答4:
thank you all for your answers!
dar7yl's solution suited my needs perfectly.
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;
回答5:
Another, messier version is using "class of type" and 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;
来源:https://stackoverflow.com/questions/757280/how-can-i-create-a-new-instance-of-a-class