Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Objekt in Komponente variabel gestalten (https://www.delphipraxis.net/193181-objekt-komponente-variabel-gestalten.html)

scrat1979 30. Jun 2017 14:01

Objekt in Komponente variabel gestalten
 
Liebe Delphi-Gemeinde,
ich habe leider keinen besseren Titel für mein Problem gefunden, Sorry. Gegeben sei eine selbst entwickelte Komponente, nennen wir sie TMyComponent. Diese beinhaltet eine abgeleitete TObjectList mit neuen eigenen Methoden. Es handelt sich bei meiner Komponente um eine TCP-Server Komponente, die FClientList soll eine Liste mit allen registrierten Clienten sein. Der Verwendungszweck spielt für mein Problem allerdings keine Rolle :-)

Delphi-Quellcode:
TMyComponent = class
 private
  FClientList : TClientList
[...]
Nun möchte ich die FClientList variabel gestalten, d.h. ich habe verschiedene "TClientLIsten", z.B. speichert die eine die Daten in einer Datenbank, die andere in einem proprietären Format über TFileStream. Meine Idee wäre hierfür eine abstrakte BasisListe a la TCustomClientList. Diese enthält alle Methoden, welche von den abgeleiteten Klassen mit Leben befüllt werden (z.B. speichert die Methode "Save" bei TFileClientList die Daten über einen TFileStream, bei TDBClientList speichert die gleichnamige Methode die Daten in eine Datenbank.) Soweit kein Problem.

Nun möchte ich meiner "TMyComponent" die Möglichkeit geben, die verschiedenen abgeleiteten Klassen von TCustomClientList zu verwenden. Dazu fallen mir folgende Möglichkeiten ein:

1. Verschiedene TMyComponent-Klassen zu erstellen und jeweils die TClientList zu ändern. Dies hätte aber zur Folge, dass eine Änderung in TMyComponent in jeder Komponente gändert werden müsste da es sich ja nicht um Vererbung handelt, sondern um verschiedene Kopien von TMyComponent.

2. Ich könnte im Constructor von TMyComponent die entsprechende Liste (TFileClientList oder TDBClientList) mitgeben. Dann müsste ich die Liste allerdings extra in der Anwendung erstellen, was ich vermeiden möchte. Außerdem wäre es dann nicht mehr möglich, die Komponente auf die Form zu "klatschen", was ich aber unbedingt beibehalten möchte (Viele Events welche ich nicht manuell "umbiegen" möchte)

Mein Frage lautet also, welche hier die Best Practice für mein Vorhaben ist. Ich brauche also mehrere "Kopien" von TMyComponent, bei denen jeweils nur die FClientList anders ist. Gibt es da eine Möglichkeit (quasi TMyComponent ableiten und jeweils die private Variable "FClientList" zu überschreiben?)

Ich hoffe ich habe mein Problem einigermaßen verständlich erklärt, bei Rückfragen einfach melden :-)

Besten Dank im Voraus!

stahli 30. Jun 2017 14:30

AW: Objekt in Komponente variabel gestalten
 
Tja, was ist Dir lieber?

Du kannst Deine TClientList als abstrakte Basisklasse auslegen und verschiedene konkrete Derivate realisieren. Oder Du kannst ein Interface IClientList verwenden.
Falls Du noch keine Erfahrungen mit Interfaces hast: Der Vorteil wäre, dass Deine konkreten ClientListen nicht von einer gemeinsamen Basisklasse stammen müssen. Dafür ist das Handling etwas aufwendiger.
Geschmacksache.

Wenn Du TMyComponent ebenfalls als Basisklasse definierst und Deine konkreten Klassen davon ableitest, könntest Du einfach 3 Controls in Deiner Palette haben und je nach Bedarf eine auf das Formular ziehen.
So wäre die Konfiguration gering. Aber Du wärst eher etwas unflexibel.

Statt dessen könntest Du eine einzelne TMyComponent erstellen und der eine Property ListKind zuordnen. Dann kann der Anwender im Objektinspektor zur Designtime eine andere Listenart auswählen und es wird dann eine neue TClientListXXX instanziiert und benutzt.

Die Frage ist, wie Du dann die einzelnen Listen mit unterschiedlichen Eigenschaften (z.B. XML-Dateiname, Datenbankzugang etc) initialisieren willst. Im Objektinspektor könnte das schwierig werden.

Das Listenobjekt zur Laufzeit zu erzeugen und zu initialisieren und dann Deiner TMyCompoment zuzuweisen ist sicher am flexibelsten.

freimatz 30. Jun 2017 16:06

AW: Objekt in Komponente variabel gestalten
 
In Ergänzung zu Stahli:
Zitat:

Zitat von scrat1979 (Beitrag 1375720)
Mein Frage lautet also, welche hier die Best Practice für mein Vorhaben ist.

Ich würde sagen seit es TFrame gibt ist es das Best Practice gar keine eigenen Komponenten zu machen. Das ist extrem aufwendig und der Nutzen relativ gering.
Was willste denn machen?

TBx 1. Jul 2017 06:51

AW: Objekt in Komponente variabel gestalten
 
Ich denke mal, dein Stichwort sollte Dependency Injection lauten.
Schau Dir z.B. mal TDataSource an, die erzeugt ihr Dataset auch nicht selber. Da klickst Du Dir die entsprechenden Komponenten auch einfach auf den Container (z.B. TDataModule) und verbindest dann über die entsprechende Property TDatasource.DataSet

Wenn das zur DesignTime unbedingt nur eine einzige Komponente sein soll, in der die Speicherart ausgewählt werden kann, so würde ich mir dazu eine separate Komponente ertellen, die die benötigten Objekte je nach Einstellung erzeugt und verbindet.

hoika 1. Jul 2017 08:00

AW: Objekt in Komponente variabel gestalten
 
Hallo,
warum so kompliziert,
solange Du nicht Generics arbeitest,
kann doch Deine TClientList verschiedene TClientListItem-Objekte enthalten.

Leite alle TClientListItem von einem gemeinsamen TCustomClientListItem ab und gut ist.

Delphi-Quellcode:
type
  TClientList = class(TObjectList)
  end;

  TCustomClientListItem = class
    public
      Typ: Integer; // welcher Typ ist es denn
  end;

  TCustomClientListItem_1 = class
    public
      im Create Typ = 1;
  end;

  TCustomClientListItem_2 = class
    public
      Typ = 2;
  end;
Typ ist eigentlich nicht notwendig, man kann ja mit is prüfen.
Das Debuggen macht es aber einfacher.

scrat1979 1. Jul 2017 09:59

AW: Objekt in Komponente variabel gestalten
 
Vielen Dank für Euer Feedback!

ich habe mir alle Vorschläge zu Herzen genommen und werde mich weiter damit beschäftigen. Ich denke, ich werde es zunächst mal so machen, dass ich die "Standard"-Liste (welche ich in 99% der Fälle auch verwende) quasi als Standard definiere und in die Komponente direkt integriere und dieser aber die Möglichkeit gebe, quasi eine "externe" TClientList zu verwenden. Dann bin ich in der Mehrzahl der Fälle ohne Mehraufwand auf der "richtigen" Seite, halte mir aber die Möglichkeit offen, jederzeit eine externe - in der Anwendung erzeugte - Liste zu verwenden.

@hoika: Deine Idee klingt interessant, momentan habe ich allerdings die Lade- und Speicherfunktion nicht in den Items, sondern in der übergeordneten Liste verpackt (Stichwort Iteration durch die einzelnen Objekte...). Dann müsste ich diese in die einzelnen Items verlegen. Hmmm.... Der Aufwand hält sich in Grenzen :-) Werde es im Verlauf auf jeden Fall mal testen.

Beste Grüße und schönes Wochenende!!!

mjustin 1. Jul 2017 10:05

AW: Objekt in Komponente variabel gestalten
 
3. Möglichkeit: die ClientList als Property deklarieren. Die verschiedenen Varianten kann man dann als Komponenten dieser Property zuweisen.
Im Designmodus kann man dann die speziellen Eigenschaften (z.B. Datenbankverbindung) definieren.

scrat1979 1. Jul 2017 14:36

AW: Objekt in Komponente variabel gestalten
 
Zitat:

Zitat von mjustin (Beitrag 1375763)
3. Möglichkeit: die ClientList als Property deklarieren. Die verschiedenen Varianten kann man dann als Komponenten dieser Property zuweisen.
Im Designmodus kann man dann die speziellen Eigenschaften (z.B. Datenbankverbindung) definieren.

Wie gesagt wollte ich es vermeiden, die ClientListe als externe Komponente einzubinden. Aber genau so wie du es vorgeschlagen hast habe ich es nun gemacht. Ich prüfe dann ob eine externe ClientList der Property zugewiesen wurde. Falls nein verwende ich die interne Liste als "Backup". Denke das ist für mich die "ideale" Lösung.

Liebe Grüße :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 05:16 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