![]() |
dynamisch Klassenkonstruktor aufrufen
Hallo,
ich will dynamisch entscheiden, von welcher Klasse ich Instanzen erzeugen will. Ist das möglich ? Dem Konstruktor sollen dabei auch Parameter übergeben werden. |
AW: dynamisch Klassenkonstuktor aufrufen
Wer zu allgemeine Fragen stellt, bekommt auch zu allgemeine Antworten: Gut dir mal die mal die
![]() |
AW: dynamisch Klassenkonstruktor aufrufen
Hallo,
< Ist das möglich ? > Ja, das ist möglich ... Um solche Klasse aber verwenden zu können, muss entweder mit Interfaces oder mit einer gemeinsamen Basisklasse gearbeitet werden. Oder mit vielen if's. Heiko |
AW: dynamisch Klassenkonstruktor aufrufen
Dafür bietet Delphi Klassenreferenzen an:
Delphi-Quellcode:
Wenn das noch dynamischer gehen soll und es Klassen aus unterschiedlichen Vererbungshierarchien mit unterschiedlichen Parametern beim Konstruktor sind, dann bleibt noch die erweiterte RTTI (ab Delphi 2010).
type
TPet = class constructor Create(const name: string); virtual; end; TPetClass = class of TPet; TDog = class(TPet); TCat = class(TPet); TParrot = class(TPet); function CreateNewPet(petClass: TPetClass; const name: string): TPet; begin Result := petClass.Create(name); end; ... var myDog: TDog; myParrot: TParrot; begin myDog := CreateNewPet(TDog, 'Rex') as TDog; myParrot := CreateNewPet(TParrot, 'Polly') as TParrot; |
AW: dynamisch Klassenkonstruktor aufrufen
Mit einer Classfactory geht das problemlos:
Delphi-Quellcode:
Verwendung:
unit ClassFactory;
interface uses SysUtils, Classes, Contnrs, SyncObjs; Type TClassFactory = Class private fCS : TCriticalSection; fClasses : TClassList; fNames : TStringList; public Constructor Create; Destructor Destroy; Override; Procedure RegisterClass(Const aClassName : String; aClass : TClass); Function GetClass (Const aClassName : String) : TClass; Function GetInstance (Const aClassName : String) : TObject; End; implementation { TClassFactory } procedure TClassFactory.RegisterClass(const aClassName: String; aClass: TClass); begin fCS.Enter; Try if fNames.IndexOf(aClassName)<>-1 then Raise exception.CreateFmt('Class %s already registered',[aClassname]); fNames.Add(aClassName); fClasses.Add(aClass); Finally fCS.Leave; End; end; constructor TClassFactory.Create; begin fClasses := TClassList.Create; fNames := TStringList.Create; fNames.CaseSensitive := False; fCS := TCriticalSection.Create; end; destructor TClassFactory.Destroy; begin fClasses.Free; fNames.Free; fCS.Free; inherited; end; function TClassFactory.GetClass(const aClassName: String): TClass; Var i : Integer; begin fCS.Enter; Try i := fNames.IndexOf(aClassName); if i=-1 then Raise Exception.CreateFmt('Class %s not registered',[aClassName]) else Result := fClasses[i]; Finally fCS.Leave; End; end; function TClassFactory.GetInstance(const aClassName: String): TObject; Var c : TClass; begin c := GetClass (aClassname); Result := C.Create; end; end.
Delphi-Quellcode:
Allerdings ist die Verwendung dieser Klassen irgendwie sinnlos, denn Du kennst ja die konkrete Schnittstelle nicht, weswegen der Zusatz von Hoika so wichtig ist.
Var
myClassFactory : TClassFactory; anApple, aPear : TObject; begin myClassFactory := TClassFactory.Create; myClassFactory.RegisterClass('Apfel', TAppleClass); myClassFactory.RegisterClass('Birne', TPearClass); ... anApple := myClassFactory.GetInstance ('Apfel'); aPear := myClassFactory.GetInstance('Birne'); ... Zitat:
|
AW: dynamisch Klassenkonstruktor aufrufen
@Dejan Vu: Und wo werden da die Parameter übergeben? Außerdem wird durch den Aufruf von TClass.Create ein überschriebener Konstruktor niemals aufgerufen, weil immer der Konstruktor von TObject aufgerufen wird (weil er ja nicht virtual ist)
Zitat:
|
AW: dynamisch Klassenkonstruktor aufrufen
Ich wollte nur eine simples Code-Pattern für eine Klassenfabrik zeigen. Ich schrieb auch, das eine solche Fabrik zwar funktioniert, aber im konkreten Fall nichts taugt, und deshalb durch eine für eine konkrete Basisklasse implementierte Fabrik ersetzt werden muss. Diese 'Basisklasse' kann man (muss man aber nicht) mit Generics abbilden, sodaß eine Implementierung reicht. Verwendung in etwa so:
Delphi-Quellcode:
Als konkrete Implementierung für Früchte kann ich dann (sofern der Konstruktor immer gleich ist), wieder mit GetInstance arbeiten.
myClass := myFactory<TFruit>.GetClass('Apfel');
myInstance := myClass.Create('Booskop', Mittelgroß, FuerEinsFuffzichDasKilo);
Delphi-Quellcode:
Nun kann man vielleicht die Parameter als 'Array Of Const' übergeben, sodaß man die generische Factory auch mit einem 'GetInstance' verwenden kann, aber da weiss ich nicht, wie man einen Konstruktorparameter dynamisch aus einem 'Array Of Const' füttert (außer, der Konstruktor akzeptiert selbst ein 'Array Of Const', was aber blöd wäre).
//
myInstance := myFruitFactory.GetInstance('Booskop', Mittelgroß, FuerEinsFuffzichDasKilo);
Delphi-Quellcode:
Du hast das bestimmt in deinem Spring-Framework gelöst (oder eben anders=besser).
//
myClass := myFactory<TFruit>.GetInstance('Apfel',['Booskop', Mittelgroß, FuerEinsFuffzichDasKilo]); Da man jedoch eine Factory auch fafür verwendet, Klassen stringent zu initialisieren, ist eine Implementierung über Generics vielleicht nicht das gelbe vom Ei. |
AW: dynamisch Klassenkonstruktor aufrufen
Ok, die Benutzung selber mit Generics aufpeppen ergibt Sinn. Ich hatte schon befüchtet, du willst die Klassen/Interfaces an sich irgendwie generisch machen :)
Zitat:
Zitat:
![]() Durch die operator Überladungen von TValue lässt sich das in vielen so Fällen benutzen, wie bei einem open array (array of const). Generell sollte man aber genau die Anforderungen definieren. Wenn man sich auf eine gemeinsame Basisklasse einigen kann, ist das sicherlich sehr gut, da man dann Typensicherheit zur Compilezeit hat und sich das RTTI Gedöns sparen kann. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:25 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz