![]() |
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. |
AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
Liste der Anhänge anzeigen (Anzahl: 1)
Etwa so?
Delphi-Quellcode:
Das erzeugen der Klasse ist eigentlich ganz einfach, solange man erst einmal die Klasse hat. Hier eine "Fabrikroutine":
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;
Delphi-Quellcode:
Im Anhand findest Du eine Konsolenanwendung, die das demonstriert. Die Möglichkeit es über die Schnittstelle zu machen, nutze ich im Beispiel aber nicht.
function CreateMeineKlasse(const Cls: TMeineKlasseClass;
const ParamStr: String): TMeineKlasse; overload; begin Result := Cls.Create(ParamStr); end; |
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. |
AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
Damit kannst du solche Spielchen treiben
Delphi-Quellcode:
Beispiele findest du bei den Grafikkomponenten.
const
meineRegistriertenKlassen: array[0..3] of TMeineKlasseClass = (TKlasse1, TKlasse2, TKlasse3, TKlasse4); {..} meineInstanz := meineRegistriertenKlassen[klassenIndex].Create; 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! |
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. |
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:
Ein Builder kann natürlich auch durch Konfigurationsdateien gesteuert werden.
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; |
AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
Ich wiederhol nochmal eine Frage zum Grundverständnis:
Zitat:
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. |
AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
Zitat:
Delphi-Quellcode:
Eine TMeineKlasse-Variable kann eine instantiierte Objektinstanz dieser Klasse oder deren Nachfahren aufnehmen,
var
Objekt: TMeineKlasse; Klasse: TMeineKlasseClass; 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) |
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.
|
AW: Zur Laufzeit erzeugte Klassen mit Parametern versorgen
Zitat:
- ![]() - ![]() 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 12: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-2025 by Thomas Breitkreuz