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.
最初我以为我可以做一些像“结果:= MyObjectTypeInstance.Create;”但由于破坏者的困难,这并没有像希望的那样工作。
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!
谢谢您的帮助!
5 个解决方案
#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.
您可能希望创建一个Abstract Factory或Factory Method类。这些是常见的设计模式,经过测试,经过验证的开发范例。
#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?
选项1 - 创建名称/类映射列表:有没有办法在delphi中通过名称实例化一个类?
Option 2 - use a 'of class' variable.
选项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
#4
thank you all for your answers!
谢谢大家的答案!
dar7yl's solution suited my needs perfectly.
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;
#5
Another, messier version is using "class of type" and TObject.ClassType
另一个更混乱的版本是使用“类型类”和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;
#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.
您可能希望创建一个Abstract Factory或Factory Method类。这些是常见的设计模式,经过测试,经过验证的开发范例。
#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?
选项1 - 创建名称/类映射列表:有没有办法在delphi中通过名称实例化一个类?
Option 2 - use a 'of class' variable.
选项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
#4
thank you all for your answers!
谢谢大家的答案!
dar7yl's solution suited my needs perfectly.
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;
#5
Another, messier version is using "class of type" and TObject.ClassType
另一个更混乱的版本是使用“类型类”和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;