2009-04-16 10 views
1

J'ai une liste d'instances de classes de différents types. Je dois être capable de créer une nouvelle instance d'une classe sans savoir avec certitude quoi créer. tous les objets impliqués ont le même ancêtre. la copie réelle des variables membres de l'objet est facile ... c'est la création du nouvel objet où j'ai un problème.Comment puis-je créer une nouvelle instance d'une classe?

il est vrai que je pouvais faire quelque chose comme ceci:

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

    obj2: 
    Result:=TObjectType2.Create; 

    obj3: 
    Result:=TObjectType3.Create; 
end; 

qui ne suivraient pas le « principe ouvert/fermé ». Au début, je pensais que je pourrais faire quelque chose comme "Résultat: = MyObjectTypeInstance.Create;" mais cela n'a pas fonctionné comme espéré à cause des difficultés des destructeurs.

est ici la dernière estimation comment je devrais faire ça ...

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; 

j'aurais pensé this'd plus facile!

je vous remercie pour votre aide!

Répondre

4

Vous voudrez probablement créer une classe de méthode Factory ou Factory abstraite. Ce sont Design Patterns courants qui sont testés, des paradigmes de développement éprouvés.

+0

oui ... bien sûr! J'aurais dû y penser! Je vous remercie! –

8

Option 1 - créer une liste de correspondances nom/classe: Is there a way to instantiate a class by its name in delphi?

Option 2 - utiliser une variable 'de la classe'.

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

merci Gabr! en fait, merci pour votre contribution massive à StackOverflow. –

11

Si toutes les classes ont un ancêtre commun, vous pouvez faire quelque chose comme ceci:

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; 

Vous pouvez utiliser tout type d'identification pour l'enregistrement de type. Tant qu'ils sont uniques.

+0

merci Gamecat! en fait, merci pour votre contribution massive à StackOverflow. –

+1

Hey, on y est ensemble ;-). Mais merci. –

2

merci à tous pour vos réponses!

La solution de dar7yl convenait parfaitement à mes besoins.

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

Merci d'avoir posté ce suivi de votre question/exemple - grandement utile aux "lurkers et 'laters' avec des questions similaires." :) – Jamo

+0

de rien. Je suis toujours reconnaissant de voir des suivis comme ça alors j'essaie de les faire moi-même! –

+0

merci pour l'exemple de code. – avar

2

Une autre version messier utilise "classe de type" et 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

Je ne l'appelle pas désordonné, mais plutôt flexible :) Je l'ai utilisé récemment pour créer des fonctions clones où la classe de base est capable de créer la bonne instance de classe enfant. –

+0

Je pense que c'est la ** vraie façon Delphi **. Assurez-vous simplement de rendre les constructeurs virtuels. Notez que la raison pour laquelle vous devez écrire TFooClass (FooA.ClassType) .Créer à la place de FooA.Create est que ce dernier n'allouera pas un nouvel objet - c'est comme ça que Delphi appelle les constructeurs hérités! –

Questions connexes