2009-04-16 64 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;