AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein dynamisch Klassenkonstruktor aufrufen
Thema durchsuchen
Ansicht
Themen-Optionen

dynamisch Klassenkonstruktor aufrufen

Ein Thema von luisk · begonnen am 24. Jul 2014 · letzter Beitrag vom 25. Jul 2014
Antwort Antwort
Benutzerbild von luisk
luisk

Registriert seit: 18. Mär 2009
402 Beiträge
 
#1

dynamisch Klassenkonstruktor aufrufen

  Alt 24. Jul 2014, 23:47
Hallo,

ich will dynamisch entscheiden, von welcher Klasse ich Instanzen erzeugen will.

Ist das möglich ?
Dem Konstruktor sollen dabei auch Parameter übergeben werden.

Geändert von mkinzler (25. Jul 2014 um 07:46 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#2

AW: dynamisch Klassenkonstuktor aufrufen

  Alt 25. Jul 2014, 00:02
Wer zu allgemeine Fragen stellt, bekommt auch zu allgemeine Antworten: Gut dir mal die mal die Creational-Pattern an.
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.275 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 07:50
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
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#4

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 08:06
Dafür bietet Delphi Klassenreferenzen an:

Delphi-Quellcode:
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;
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).
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight

Geändert von Stevie (25. Jul 2014 um 08:37 Uhr)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#5

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 08:08
Mit einer Classfactory geht das problemlos:
Delphi-Quellcode:
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.
Verwendung:
Delphi-Quellcode:
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');
...
Allerdings ist die Verwendung dieser Klassen irgendwie sinnlos, denn Du kennst ja die konkrete Schnittstelle nicht, weswegen der Zusatz von Hoika so wichtig ist.
Um solche Klasse aber verwenden zu können, muss entweder mit Interfaces oder mit einer gemeinsamen Basisklasse gearbeitet werden.
Das o.g. Pattern (die class factory) sollte man also für eine konkrete Basisklasse (oder noch besser: Interface) erstellen. Das geht über Generics sehr elegant.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#6

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 08:38
@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)

Das o.g. Pattern (die class factory) sollte man also für eine konkrete Basisklasse (oder noch besser: Interface) erstellen. Das geht über Generics sehr elegant.
Das versteh ich nicht. Was hat das jetzt mit Generics zu tun?
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#7

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 08:56
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:
  myClass := myFactory<TFruit>.GetClass('Apfel');
  myInstance := myClass.Create('Booskop', Mittelgroß, FuerEinsFuffzichDasKilo);
Als konkrete Implementierung für Früchte kann ich dann (sofern der Konstruktor immer gleich ist), wieder mit GetInstance arbeiten.
Delphi-Quellcode:
  //
  myInstance := myFruitFactory.GetInstance('Booskop', Mittelgroß, FuerEinsFuffzichDasKilo);
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).
Delphi-Quellcode:
  //
  myClass := myFactory<TFruit>.GetInstance('Apfel',['Booskop', Mittelgroß, FuerEinsFuffzichDasKilo]);
Du hast das bestimmt in deinem Spring-Framework gelöst (oder eben anders=besser).

Da man jedoch eine Factory auch fafür verwendet, Klassen stringent zu initialisieren, ist eine Implementierung über Generics vielleicht nicht das gelbe vom Ei.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.016 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#8

AW: dynamisch Klassenkonstruktor aufrufen

  Alt 25. Jul 2014, 09:11
Ok, die Benutzung selber mit Generics aufpeppen ergibt Sinn. Ich hatte schon befüchtet, du willst die Klassen/Interfaces an sich irgendwie generisch machen

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).
Geht, tut man sich aber keinen allzu großen Gefallen mit, da man vieles wieder auseinander pflücken muss.

Du hast das bestimmt in deinem Spring-Framework gelöst (oder eben anders=besser).
Es gibt dort den TActivator (der Activator Klasse aus .Net nachempfunden), mit der man das machen kann (entsprechend meines Hinweises auf enhanced RTTI weiter oben). Parameter werden über ein array of TValue weitergegeben.
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.
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:52 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz