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/)
-   -   Delphi Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik (https://www.delphipraxis.net/197822-interface-und-klassenstruktur-fuer-entkoppelte-gui-und-anwendungslogik.html)

Aviator 7. Sep 2018 13:36

Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Delphianer,

ich hoffe der Thread Titel ist nicht zu abschreckend. Ich konnte aber leider keine bessere Zusammenfassung finden.

Ich bräuchte etwas Hilfe bei der Erstellung meiner Interface- und Klassenstruktur. Mit meinem Programm soll es machbar sein, dass diverse Daten von mehreren an den PC, per USB/Netzwerk/whatever, angeschlossenen Geräten ausgelesen werden können. Hierbei handelt es sich nicht um irgendwelche Laufwerke (wie USB-Sticks, HDDs, ...) sondern um Eigenentwicklungen mit eigener Software und Hardware.

So gesehen noch nicht dramatisch, aber es ist nicht nur ein Gerätetyp, sondern es können mehrere sein. Demzufolge haben diese Geräte auch unterschiedliche Parameter und Daten/Werte die ausgelesen bzw. geschrieben werden müssen.

Also habe ich mich dazu entschlossen, ein DLL System aufzubauen um das ganze problemlos(?) erweiterbar zu machen ohne die Hauptanwendung antasten zu müssen. Diese DLLs geben eine Interface Instanz
Delphi-Quellcode:
IDataCollector
zurück. Die DLL ist dann also für das Sammeln der Daten von den jeweiligen Geräten zuständig. Das bedeutet, dass es pro Gerät (bzw. pro Hardware welche andere Parameter hat) eine DLL gibt.

Das Speichern der Daten würde auch von der DLL übernommen werden, da die Werte sehr wahrscheinlich auch in unterschiedliche Tabellen geschrieben werden müssen. Hier bin ich aber auch für Anregungen offen und dankbar. Mir persönlich wäre z.B. eine einzelne
Delphi-Quellcode:
IDataSaver
Instanz lieber, die das Speichern in die Datenbank übernimmt. Eventuell könnte ich das so lösen, dass ich nur das Statement übergebe und die Interaktion mit der Datenbank wird in eine separate DLL ausgelagert welche für alle gleich ist. Hier wäre dann aber der verwendete Server ein Problem wenn von bspw. MSSQL auf PostgreSQL umgestellt werden müsste. Demzufolge dürfte auch hier wiederum nur ein Interface übergeben werden. Aber dann bin ich prinzipiell an dem nachfolgenden Punkt:


Jetzt zum eigentlichen Problem, welches aber eventuell auch die angesprochene Thematik des speicherns der Daten in der Datenbank lösen/vereinfachen könnte:

Die Daten die von den Geräten ausgelesen wurden, müssen ja auch mal wieder angezeigt oder geändert werden. Entweder direkt als Daten aus der DLL oder später aus der Datenbank heraus. Jetzt stellt sich mir die Frage, wie ich das am besten löse. Jedes Gerät hat ja wie angesprochen seine eigenen Parameter/Werte. Nur wie kann ich es anstellen, dass meine GUI so flexibel ist und sich daran anpasst? Es gibt ja alphanumerische Felder (TEdit) oder reine Integer Felder (TEdit oder TSpinEdit) oder eventuell auch Auswahlmenüs (TComboBox). Die Tabellen sind ja pro Gerät evtl. auch unterschiedlich, also müsste das über einen passenden Service geregelt werden der die benötigten Daten abruft.

Aktuell sieht es so aus, dass ich die Struktur zum Auslesen der Daten habe (s. Bild). Programmiert ist noch nichts, ich mache mir nur gerade Gedanken über den Aufbau.

Anhang 49893

Im Hauptprogramm gibt man an von welchem Gerätetyp die Daten ausgelesen werden sollen. Über eine Factory wird bestimmt, welcher DataCollector geladen werden muss. Diese Information erhält er wahrscheinlich aus der Datenbank, weil dort die DLL mit Namen registriert werden muss damit sie geladen werden kann. Wenn der DataCollector geladen wurde, kann dieser seinerseits natürlich auch wieder weitere DLLs für die verschiedenen Anwendungszwecke nachladen. Das ist dann aber dem DataCollector überlassen. Er kann prinzipiell auch direkt mit dem Gerät kommunizieren. Wichtig ist nur die Rückgabe/Speicherung der Daten (bei der ich wie gesagt keine Idee habe wie ich das realisieren kann).

Ich hoffe ihr könnt mir da irgendwie unter die Arme greifen und mir helfen, dass Problem zu lösen. :)

PS: Das hier war mal so ein erster Entwurf wie das IDataCollector Interface aussehen könnte. Es ist nicht wirklich viel, weil ich den Rückweg auch noch nicht kenne.

Delphi-Quellcode:
IDataCollector = interface
[GUID]
  function Collect: Integer;
  function GetLastError: Integer;
  function SaveToDataBase: Integer; // Diese Procedure müsste eigentlich ausgelagert werden
  function SaveToFile(const FileName: string): Integer;  // Diese Procedure müsste eigentlich ausgelagert werden
end;

Danke fürs Lesen und ich hoffe auf viel Input. Wenn Fragen aufkommen, dann bitte einfach stellen. Vielleicht habe ich ja im Eifer des Gefechts die Hälfte vergessen. :stupid:

Ghostwalker 8. Sep 2018 05:16

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Ich würde das ganze über ein weiteres Interface machen, das dir letztlich eine Liste mit Felder liefert (wird auch über die Geräte-DLL erzeugt).

Diese Liste liefert dir für jeden gerätespecifischen Paremter so sachen wie den Namen des Feldes, den Typ (Integer, String, Enum usw) sowie das Value. Damit kannst du die Gui dynamisch erzeugen.

Die gleiche Liste kannst du auch an eine Datenbank-DLL weiterreichen, die dir das ganze dann speichert.

Das ganze könnte ungefähr so aussehen:

Gemeinsame Typen (über alle DLL's und der APP)

Delphi-Quellcode:
Type
  TDataField = Record
             Name : string;
             Type : String;
             value: TValue;
  end;

  TFieldList = TList<TDataField>;

  TDataList = TList<TFieldList>;
Interfaces
Delphi-Quellcode:
  //Sammeln der Daten
  IDataCollector = Interface
  [GUID]
  function Collect:integer;
  function GetLastError:Integer;
  function GetData:TDataList;
  end;

  //Speichern der Daten IRGENDWO
  IDataSaver = Interface
  [GUID]
  function SetDataList(data:TDataList):boolean;
  Procedure Save;
  end;

  //Laden der Daten von IRGENDWO
  IDataLoader = Interface
  [GUID]
  Procedure Load;
  Function GetDataList:TDataList;
Damit kannst du das ganze handhaben, ohne das deine App die konkrete Struktur der Gerätedaten kennt. Und über die beiden anderen Interfaces kannst es sogar soweit treiben, das die App nocht nicht mal weiß, wo die Daten gespeichert werden, den ob das dann in einer Datenbank oder einer Datei oder in die Cloud ist, ist hier auch egal, solange das ganze die entsprechenden Interfaces liefert.

Aviator 8. Sep 2018 11:17

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Hi, danke für die Antwort. :thumb:

Über so ein zusätzliches Interface das mir die Felder mit Bezeichnung, Datentyp und Wert liefert habe ich auch schon nachgedacht. Nur wusste ich nicht, ob das wirklich "best practice" ist oder ich das total umständlich mache. Allerdings würde das ja auch wirklich das Problem mit dem Speichern der Daten auf den Server beheben wie ich es im Ausgangspost schon beschrieben hatte.

Ich versuche mal meine Planung auf diesem Verfahren aufzusetzen. Mal schauen ob ich damit soweit alles abdecken kann.

Wenn es noch andere - vielleicht sogar bessere - Ideen gibt, bin ich natürlich offen dafür.

freimatz 10. Sep 2018 09:43

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Ich gebe zu, dass ich das Problem kaum verstanden habe. Allerdings kann ich sagen dass bei uns nahezu alle Klassen auch ein Interface haben und Kontrakt und Implementierung zu trennen (und Referenzzählung zu haben).

stahli 10. Sep 2018 10:23

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Ich hatte bei der Überschrift aufgehorcht, da Databinding ein wenig mein Steckenpferd geworden ist. :-)

Die Problembeschreibung hatte ich dann aber nicht verstanden.

Vielleicht hilft folgende Überlegung noch etwas weiter:

Die Geräte könnten auch Anweisungen für den Formularaufbau mitschicken (Edit1, an Position X/Y, gebunden an Wert Z; Button1, an Position X/Y, Beschriftung=OK, Action=SaveData)

So muss das Hauptformular nicht wissen, was es wie genau darstellen muss.

Die Frage des konkreten tatsächlichen Datenaustausches ist damit natürlich nicht geklärt.

Aviator 10. Sep 2018 11:00

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Naja es geht darum, dass für unterschiedliche Geräte unterschiedliche Werte abgerufen werden müssen. Diese Werte sollen aber auch anzeigbar und editierbar sein. Wenn aber nur die DLL selbst weiß, welche Werte vom Geräte abgerufen werden müssen, dann kann die GUI nichts anzeigen weil die Felder ja nicht existieren.

Also muss die DLL im Prinzip der GUI mitteilen, welche Felder vorhanden sein müssen und welche Werte diese haben.

Mit dem Ansatz den Ghostwalker mir geliefert hat, kann ich denke ich auch schon etwas anfangen. Zumindest versuche ich es mal.

Zitat:

Zitat von freimatz (Beitrag 1412816)
Ich gebe zu, dass ich das Problem kaum verstanden habe. Allerdings kann ich sagen dass bei uns nahezu alle Klassen auch ein Interface haben und Kontrakt und Implementierung zu trennen (und Referenzzählung zu haben).

Habt ihr denn auch eine GUI die sich abhängig von irgendwelchen Werten anpassen muss? Also neue Felder erstellen usw.? Das würde mich dann interessieren. Wie sieht so etwas bei euch aus?

Zitat:

Zitat von stahli (Beitrag 1412826)
Vielleicht hilft folgende Überlegung noch etwas weiter:

Die Geräte könnten auch Anweisungen für den Formularaufbau mitschicken (Edit1, an Position X/Y, gebunden an Wert Z; Button1, an Position X/Y, Beschriftung=OK, Action=SaveData)

Das wäre dann prinzipiell das, was Ghostwalker auch schon vorgeschlagen hatte. In die Richtung ging beim erster Gedanke auch schon, nur habe ich den im Ausgangspost nicht beschrieben um nicht irgendjemandem Worte in den Mund zu legen. :wink:

Jumpy 10. Sep 2018 12:20

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Wenn man eine Query über eine Datasource mit einem Grid verbindet, macht man ja mMn was ähnliches, das Grid hat die richtige Anzahl spalten und die Daten werden passend angezeigt. Vielleicht kann man sich da inspiration holen. Oder man tauscht die Daten zw. Anwendung und DLL JSON-artig aus und baut dann eine Adapterklasse, die daraus eine GUI machen kann.

jobo 10. Sep 2018 13:27

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Mir fällt bei den "Geräten" mit spezifischen Eigenschaften und DLL eher ein hierarchischer Key Value Store ein. Die DLL müsste also eine Art Baumstruktur liefern, z.b. in JSON oder so.
Visualisierung im Client dann z.B. mit (Virtual ) TreeView. Die Ebene eines Zweiges könnte dann ggf. als Form angezeigt/generiert werden.
Bei dem Ganzen müsste man vermutlich auch noch unterscheiden, welche Infos vom Gerät geliefert wurden/werden müssen und welche insgesamt definiert sind, also optionale Werte berücksichtigen. Das müsste spätestens die spezifische DLL wissen oder noch flexibler (bei neuer Firmware, ..), eine JSON Schema Definition.

Aviator 10. Sep 2018 13:44

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Das Ganze mit JSON abzuwickeln und dann daraus eine GUI zu bauen hat natürlich auch etwas. Vor allem bin ich dann etwas unabhängiger von der Programmiersprache in der die DLL entwickelt wird. Ist noch etwas flexibler als die Interface Lösung von Ghostwalker (mit der ich auch geliebäugelt hatte) denke ich. Hat sowas schon mal jemand von euch gemacht?

Wie würdet ihr dann den JSON String am besten von der DLL zur Anwendung übertragen? Einfach eine Funktion die einen
Delphi-Quellcode:
string
respektive
Delphi-Quellcode:
PChar
liefert, oder gibt es da andere Ansätze? ShareMem sollte nicht zum Einsatz kommen, da evtl. auch aus C# DLLs gelesen werden muss. Einen REST Service oder so pro DLL erstellen zu müssen halte ich für überzogen. Eine Datei ablegen aus der wieder gelesen wird finde ich auch unschön. Das sollte schon alles im Memory passieren.

Bin für jede Idee dankbar. :thumb:

jobo 10. Sep 2018 14:17

AW: Interface- und Klassenstruktur für entkoppelte GUI und Anwendungslogik
 
Man könnte es vielleicht URL artig machen (ohne http server natürlich). Vgl Registry.
Adresse (bzw. Key) setzen und Wert oder Wert Liste abfragen. Damit könnte man sich in Unkenntnis der Struktur bis in jedes Blatt hangeln.
Je nach zu erwartendem Volumen auch einfach alles holen.
Technisch bräuchte man nur einen Datentyp, der JSON encoding respektiert bzw. man muss sich im Interface darauf einigen, wie der String am Ende zu handhaben ist.


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