2009-04-16 27 views
1

Ich habe eine Liste von Klasseninstanzen verschiedener Art. Ich muss in der Lage sein, eine neue Instanz einer Klasse zu erstellen, ohne genau zu wissen, was ich erstellen soll. Alle beteiligten Objekte haben denselben Vorfahren. Das eigentliche Kopieren der Objektvariablen des Objekts ist einfach ... es ist die Erstellung des neuen Objekts, wo ich ein Problem habe.Wie kann ich eine neue Instanz einer Klasse erstellen?

allerdings könnte ich so etwas tun:

case MyObjectTypeInstance.MyTypeEnum of 
    obj1: 
    Result:=TObjectType1.Create; 

    obj2: 
    Result:=TObjectType2.Create; 

    obj3: 
    Result:=TObjectType3.Create; 
end; 

, die das „offen/geschlossen-Prinzip“ nicht folgen würden.

ursprünglich dachte ich, ich könnte etwas wie "Ergebnis: = MyObjectTypeInstance.Create;" aber das funktionierte nicht wie erhofft wegen Zerstörungsschwierigkeiten.

hier ist die letzte Vermutung, wie ich dies tun ...

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 this'd einfacher hätte gedacht werden sollte!

danke für Ihre Hilfe!

Antwort

4

Sie möchten wahrscheinlich eine Abstract Factory oder Factory Method-Klasse erstellen. Diese sind üblich Design Patterns die getestet werden, bewährte Entwicklungsparadigmen.

+0

ja ... natürlich! Ich hätte daran denken sollen! Danke! –

8

Option 1 - erstellen Sie eine Liste von Namen/Klasse Zuordnungen: Is there a way to instantiate a class by its name in delphi?

Option 2 - verwenden, um ein 'der Klasse' 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 
+1

danke Gabr mit! Vielen Dank für Ihren massiven Beitrag zu StackOverflow. –

11

Wenn alle Klassen einen gemeinsamen Vorfahren haben, können Sie etwas tun:

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; 

Sie jede Art von Identifikation für den Typ Registrierung verwenden können. Solange sie einzigartig sind.

+0

danke Gamecat! Vielen Dank für Ihren massiven Beitrag zu StackOverflow. –

+1

Hey, wir sind zusammen drin ;-). Aber danke. –

2

Vielen Dank für Ihre Antworten!

Die Lösung von dar7yl ist perfekt auf meine Bedürfnisse abgestimmt.

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

Vielen Dank für das Posten dieses Follow-up zu Ihrer Frage/Beispiel - sehr hilfreich für "Lurkers und 'Laters' mit ähnlichen Fragen." :) – Jamo

+0

Gern geschehen. Ich bin immer dankbar, Folgeaktionen zu sehen, also versuche ich sie selbst zu machen! –

+0

danke für das Codebeispiel. – avar

2

Eine weitere, Messier-Version ist "Klasse vom Typ" und 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; 
+0

Wäre nicht unordentlich, sondern eher flexibel :) Ich habe es vor kurzem verwendet, um Klon-Funktionen zu erstellen, bei denen die Basisklasse die richtige Kindklasseninstanz erstellen kann. –

+0

Ich denke, das ist der ** wahre Delphi Weg **. Stellen Sie sicher, dass die Konstruktoren virtuell sind. Beachten Sie, dass der Grund, warum Sie TFooClass (FooA.ClassType) .Create anstelle von FooA.Create schreiben müssen, ist, dass letzteres kein neues Objekt zuweist - so nennt Delphi geerbte Konstruktoren! –

Verwandte Themen