2009-04-16 60 views
1

我有各种类的实例列表。我需要能够创建一个新的类的实例,而不必知道要创建什么。所涉及的所有对象都具有相同的祖先。对象的成员变量的实际复制很容易...这是创建新的对象,我有一个问题。我如何创建一个类的新实例?

诚然,我可以做这样的事情:

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; 

我会一直this'd认为是更容易!

谢谢你的帮助!

回答

4

您可能会想要创建一个Abstract Factory或Factory Method类。这些都是通用的Design Patterns这是经过验证的开发范例。

+0

是的......当然!我应该想到这一点!谢谢! – 2009-04-16 19:53:28

8

选项1 - 创建名称/类映射的列表:Is there a way to instantiate a class by its name in delphi?

选项2 - 使用一个 '类' 变量。

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 
+1

谢谢贾布尔!实际上,感谢您对StackOverflow的巨大贡献。 – 2009-04-16 19:59:53

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; 

你可以使用任何类型的鉴定类型注册。只要它们是独一无二的。

+0

谢谢你Gamecat!实际上,感谢您对StackOverflow的巨大贡献。 – 2009-04-16 19:59:20

+1

嘿,我们在一起;-)。但是,谢谢。 – 2009-04-16 20:21:57

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; 
+0

感谢您发布此问题的后续问题/示例 - 对于“潜伏者和具有类似问题的'laters'”非常有帮助。“ :) – Jamo 2009-04-16 23:40:45

2

另外,混乱版本使用 “类类型” 和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;