Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Zur Laufzeit erzeugte Klassen mit Parametern versorgen (https://www.delphipraxis.net/166980-zur-laufzeit-erzeugte-klassen-mit-parametern-versorgen.html)

Jumpy 8. Mär 2012 10:34

Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Hallo und guten morgen erstmal...

Mir fehlen mal wieder die richtigen Schlagworte/Konzepte/Grundlagen:

Ich möchte zur Laufzeit verschiedene Klassen (eigentl. Objekte, klar) erzeugen. Welche das sind soll von außen gesteuert werden, z.B. über eine Konfig-Tabelle. Ich lese mir dazu nochmal was zu Klassenfabriken durch und denke, dass ich das hin kriege.
Die Klassen werden von einer gemeinsamen Basisklasse erben oder dasselbe Interface implementieren, so dass ich mit ihnen weiterarbeiten kann (ggf. weiterhin ohne zu wissen, welche konkrete Klasse ich gerade habe).

Das Problem ist, dass die Klassen zum arbeiten unterschiedliche Angaben brauchen und die Frage ist: wie krieg ich die denen übermittelt?

Ich könnte in der Konfig-Datei neben dem Klassennamen einen Parameterstring speichern und der Klasse nach der Erzeugung übergeben. In einer öffentl. Prozedur oder Property (ginge das?), die über das Interface bekannt wäre. Die jeweilige Implementation der Funktion in der konkreten Klasse, muss dann dafür sorgen, das der Parameterstring korrekt zerlegt wird.

Oder ich speichere in der Konfig-Datei zusätzlich eine ID und gebe die bei der Klassenerzeugung mit an. Zu jeder Klasse könnte es dann eine (immer anders aufgebaute) Tabelle geben, aus der sich die Klasse selber über die ID, ihre Parameter holt. (Wäre dann sowas wie ein Mini-ORM, oder?).

Oder ein ganz anderer Ansatz oder Konzept, dass ich nicht kenne, vllt? Ich hab dafür Delphi2010 zur verfügung, also ginge auch was mit RTTI, obwohl ich da bisher kaum Ahnung vonhab.

Panthrax 8. Mär 2012 12:28

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Etwa so?

Delphi-Quellcode:
type
  IMeineSchnittstelle = interface

  end;

  TMeineKlasse = class(TInterfacedObject, IMeineSchnittstelle)
  strict protected
    function GetValueAsString: String; virtual; abstract;

  public
    property ValueAsString: String read GetValueAsString;

    constructor Create(const ParamStr: String); virtual; abstract;
  end;

  TMeineKlasseClass = class of TMeineKlasse;

  TNativeIntNachkomme = class(TMeineKlasse)
  strict private
    FValue: NativeInt;

  strict protected
    function GetValueAsString: String; override;

  public
    constructor Create(const ParamStr: String); override;
  end;

  TStringNachkomme = class(TMeineKlasse)
  strict private
    FValue: String;

  strict protected
    function GetValueAsString: String; override;

  public
    constructor Create(const ParamStr: String); override;
  end;
Das erzeugen der Klasse ist eigentlich ganz einfach, solange man erst einmal die Klasse hat. Hier eine "Fabrikroutine":
Delphi-Quellcode:
function CreateMeineKlasse(const Cls: TMeineKlasseClass;
  const ParamStr: String): TMeineKlasse; overload;
begin
  Result := Cls.Create(ParamStr);
end;
Im Anhand findest Du eine Konsolenanwendung, die das demonstriert. Die Möglichkeit es über die Schnittstelle zu machen, nutze ich im Beispiel aber nicht.

Jumpy 8. Mär 2012 13:04

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Bevor ich mir die Demo anguck, schonmal schnell gefragt:

Was genau macht eigentlich:
Delphi-Quellcode:
TMeineKlasseClass = class of TMeineKlasse;


Und woher weiß die Fabrikroutine, ob sie jetzt einen StringNachkommen oder einen IntNachkommen erzeugen soll?
Ziehe die Frage nach durchlesen der Demo zurück.

Aphton 8. Mär 2012 15:04

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Damit kannst du solche Spielchen treiben
Delphi-Quellcode:
const
  meineRegistriertenKlassen: array[0..3] of TMeineKlasseClass = (TKlasse1, TKlasse2, TKlasse3, TKlasse4);
{..}
  meineInstanz := meineRegistriertenKlassen[klassenIndex].Create;
Beispiele findest du bei den Grafikkomponenten.
Der hat intern auch eine Liste (Array), in der für jedes Format (bmp, jpg, png, ...) eine Klasse drinnen steht. Willst du nun ein Bild laden, so erkennt der, welcher "Loader" notwendig ist, instanziert diesen und lädt anschließend.
Fein ist es auch, dass man ganz einfach seine eigenen Formate registrieren kann usw. (ich drifte ab).
Du solltest es verstanden haben!

himitsu 8. Mär 2012 15:34

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Oder da wo die Grafikklassen bei TPicture angemeldet sind, mit ihren Dateiendungen, so daß TImage/TPicture sich dann die passende Klasse zur Dateiendung raussuchen kann.

Oder TComponent der VCL, wo die VCL alle TComponent-Nachfahren problemlos erstellen und befüllen kann.

shmia 8. Mär 2012 17:37

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Vielleicht suchst du auch das Builder-Design-Pattern.
Ein Builder ist eine Klasse, die ein oder mehrere Objekte in mehreren Schritten erstellen kann.

Kleines Beispiel:
Delphi-Quellcode:
TCarBuilder = class(TObject)
public
  procedure AddChassis(lenght,width:integer);
  procedure AddEngine(horsepower:double);
  procedure SetColor(color:TColor);
  procedure AddTyres(diameter:integer);

  function GetCar:TCar;
end;

var
  builder : TCarBuilder;
  newcar : TCar;
begin
  builder := TCarBuilder.Create;
  // Schrittweise zusammenbauen
  builder.AddChassis(460, 165);
  builder.AddEngine(210.0 {PS});
  builder.SetColor(clBlack);
  builder.AddTyres(19 {Zoll});
  // und Ergebnis abholen
  newcar := builder.GetCar;
Ein Builder kann natürlich auch durch Konfigurationsdateien gesteuert werden.

Jumpy 9. Mär 2012 11:43

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Ich wiederhol nochmal eine Frage zum Grundverständnis:
Zitat:

Zitat von Jumpy (Beitrag 1155377)
Was genau macht eigentlich:
Delphi-Quellcode:
TMeineKlasseClass = class of TMeineKlasse;

Generell dieses "class of"? TMeineKlasse ist doch schon die Klasse, die ich brauche. Was ist dann TMeineKlasseClass?


Und dann noch eine Frage zu Fabriken (da ich durch die ganzen "verweiste Referenzen"-Threads der letzten Zeit etwas verwirrt bin). Eine Fabrik erzeugt ein Objekt und "gibt dass nach aussen an eine andere Klasse weiter" (Wenn man so will an den Kunden der Fabrik). Jetzt gibt es doch 2 Referenzen auf das Objekt. Wer gibt das Objekt später wieder frei und wie erfährt der andere davon?

@shmia: Das passt in dem Fall den ich im Kopf habe, glaub ich erstmal nicht, da es doch schon verschiedene Klassen sind, die die Fabrik erstellen soll und nicht eine Klasse mit unterschiedlichen Werten, wie der Builder das mMn macht.

himitsu 9. Mär 2012 11:59

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Zitat:

Zitat von Jumpy (Beitrag 1155608)
Zitat:

Zitat von Jumpy (Beitrag 1155377)
Was genau macht eigentlich:
Delphi-Quellcode:
TMeineKlasseClass = class of TMeineKlasse;

Generell dieses "class of"? TMeineKlasse ist doch schon die Klasse, die ich brauche. Was ist dann TMeineKlasseClass?

Delphi-Quellcode:
var
  Objekt: TMeineKlasse;
  Klasse: TMeineKlasseClass;
Eine TMeineKlasse-Variable kann eine instantiierte Objektinstanz dieser Klasse oder deren Nachfahren aufnehmen,
während TMeineKlasseClass die Klasse selber aufnehmen kann, oder einen ihrer Nachfahren.
Delphi-Quellcode:
if X then
  Klasse := TMeineKlasse
else
  Klasse := TMeineNachfahrKlasse;

Objekt := Klasse.Create;

Klasse.Klassenprozedur(123); // ausführen einer Class Procedure/Function dieses Types aus (natürlich praktisch, wenn das ding dann virtual wäre)

DeddyH 9. Mär 2012 12:02

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Durch das class off kannst Du Dir einen "Oberbegriff" für die Art der zu erstellenden Objektklasse definieren. Brauchst Du eine Instanz von TDings, übergibst Du TDings als Parameter, soll es TBums sein, dann eben TBums. Ohne das class of müsstest Du ja für jeden Typ eine überladene Methode schreiben, so kannst Du die Klasse einfach festlegen.

stahli 9. Mär 2012 13:11

AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
 
Zitat:

Zitat von Jumpy (Beitrag 1155608)
Und dann noch eine Frage zu Fabriken (da ich durch die ganzen "verweiste Referenzen"-Threads der letzten Zeit etwas verwirrt bin). Eine Fabrik erzeugt ein Objekt und "gibt dass nach aussen an eine andere Klasse weiter" (Wenn man so will an den Kunden der Fabrik). Jetzt gibt es doch 2 Referenzen auf das Objekt. Wer gibt das Objekt später wieder frei und wie erfährt der andere davon?

Ich denke mal, dass Du Dich hierauf beziehst:
- http://www.delphipraxis.net/166899-i...eferenzen.html
- http://www.delphipraxis.net/159095-r...e-objekte.html

Grundsätzlich sehe ich mehrere Möglichkeiten:

1) Du verwaltest keine festen Referenzen auf ein bestimmtes Objekt, sondern nur eine Id. Bei Bedarf forderst Du bei einem "Broker" anhand der ID das entsprechende Objekt ab und bekommst dieses oder nil geliefert. In deiner aktuellen Methode kannst Du dann mit dem Rückgabewert arbeiten.
Der "Broker" kann dann die Objekte eine bestimmte Zeit zwischenspeichern und irgendwann wieder verwerfen.
Die Objekte müssen sich also nicht dauerhaft im Speicher befinden sondern können bei Bedarf neu erzeugt und mit Daten aus einer Datenbank "befüllt" werden (ORM).
Da Du keine festen Referenzen verwaltest, brauchst Du auch keine Referenzen auf nil setzen, wenn Du ein Objekt auflöst.

2) Eine etwas halbherzigere Lösung wäre, alle erzeugten Objekte (einer bestimmten Sorte) in einer Liste zu speichern und beim Auflösen wieder daraus zu entfernen. Dann kann man bei jedem Zugriff auf eine Objektreferenz prüfen, ob sich das Objekt noch in der "Gültigkeitsliste" befindet. Statt Assign(o) könnte man sich eine Funktion Exist(o) deklarieren.

3) Wenn Du mit reinen Objekten arbeitest und diese gegenseitig referenzierst, dann kannst Du mit einem Observer-Pattern referenzierende Objekte bei referenzierten Objekten anmelden (in einer Liste eintragen). Wird das referenzierte Objekt aufgelöst, werden alle referenzierenden Objekte zuvor darüber unterrichtet und setzen die entsprechende Eigenschaft auf nil. Das muss man jedoch alles von Hand regeln und dafür entsprechende Listen und Methoden einführen.

4) Anstatt Objekte kann man Interfaces verwenden, welche einige Vorteile haben allerdings auch einigen Mehraufwand mit sich bringen. Interfaces werden sozusagen automatisch überwacht und wenn kein Interface auf ein Objekt mehr verwendet wird, wird das Objekt freigegeben (jedenfalls in Delphi).

EDIT: Ach so, und die Lösung von Thom unter dem ersten Link, die die Ansätze 3 + 4 miteinander verbindet.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:43 Uhr.
Seite 1 von 2  1 2      

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