Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Trennung von GUI und Logik (https://www.delphipraxis.net/200525-trennung-von-gui-und-logik.html)

Maekkelrajter 28. Apr 2019 15:17

Trennung von GUI und Logik
 
Seit vielen Jahren, um nicht zu sagen Jahrzehnten programmiere ich hobbymäßig und vorwiegend für den Eigenbedarf. Das begann 1987 mit dem 64er (Basic, Assembler). Es folgte der Amiga (Basic, GFA-Basic, Assembler) und schließlich diverse PCs ( Assembler,TP 6 , BP 7, Delphi 1, 2, 4, 10). Meist waren das kleinere Anwendungen, für die natürlich vorher kein Konzept erstellt wurde, sondern nach Erstellung der Infrastruktur (GUI, IO-Routinen) mit möglichst wenig Zeitaufwand die gewünschte Funktionalität implementiert wurde. Immer wieder kam es allerdings vor, dass gerade solche q&d hingerotzte Sachen dann im Laufe der Zeit immer weiter wuchsen, um nicht zu sagen wucherten. Dabei versuchte ich natürlich immer, gewisse Mindeststandards einzuhalten, was Strukturierung und Modularisierung betraf, sodass ich auch nach Jahren weitgehend die Übersicht behielt. Da ich das Ganze, wie gesagt, hobbymäßig betreibe, konnte ich auch viel Zeit mit 'Refactoring' verbringen, wobei sowohl GUI als auch der Programmcode immer wieder optimiert und 'verschönert' , soll heißen 'profimäßiger' ( oder was ich dafür hielt) gestaltet wurde. Dennoch fürchte ich, ein professioneller Entwickler würde beim Anblick mancher meiner Sources einen Schreikrampf erleiden, aber damit kann ich leben. Denn für mich ist der Hauptzweck erfüllt: Die Funktionalität ist wunschgemäß, die Optik ist ansprechend und das GUI funktional und gut bedienbar. Ich kann das Programm nutzbringend für mich einsetzen und nicht nur IT-Laien damit schwer beeindrucken ;-)
Wie sicher mancher schon ahnt, bin ich auch nicht der Großmeister der OOP.
Daher rührt auch mein aktuelles Problem. In meinem aktuellen Projekt möchte ich eine weitgehende Trennung von GUI und Logik durchführen. Mich stört vor allem die grotesk aufgeblähte Deklaration des Hauptformulars, das einen großen Teil der Logik in den OnClick - Handlern bzw. deren Implementation enthält. Bei eienem großen Teil von ihnen ließ sich der Code leicht in separate Units bzw. Klassen auslagern, was das Ganze schon erheblich übersichtlicher macht. Aber jetzt sollen doch Nägel mit Köpfen gemacht und sämtliche Logik aus der Mainform - Deklaration und -Implementierung entfernt werden.
Ein Problem sind für mich die Routinen, die während der oft sekunden- oder gar minutenlangen Dauer ihrer Ausführung auf Komponenten des Hauptformulars zugreifen und etwa Zählerstände in TLabels oder Textausgaben in TMemos aktualisieren, was als Lebenszeichen der Anwendung, quasi als Fortschritts-Anzeige, und auch zur Information des Anwenders unerläßlich ist.

Beispiel:
Delphi-Quellcode:
unit DemoForm;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    Memo1: TMemo;
    // 128 Deklarationen
    procedure Button1Click(Sender: TObject);
    // 100 Event- Handler
  private
    { Private-Deklarationen }
    // 116 Deklarationen (schon teilweise reduziert)
  public
    { Public-Deklarationen }
    // 2 Deklarationen
  end;

var
  Form1: TForm1;

implementation


//Beispiel: Durchsuche eine iTunes Mediathek mit 10000 Tracks nach Tracks ohne Albumcover (Pseudocode)

procedure TForm1.Button1Click(Sender: TObject);
  var i: Integer;
begin
  {
   for i := 1 to 10000 do
     begin                                                                                                                                
       label1.caption:= inttostr(i);                                             // erhöhe den Zählerstand im Label                                      
       If Track(i) ohne Albumcover Then Memo1.lines.add(Titel +  Artist + Album) // Wenn einer gefunden, Track (Titel, Artist, Album) im Memo ausgeben
     end;
  }
end;

end.
Wie schaffe ich es nun, den Code aus dem OnClick - Handler auszulagern und dennoch Zugriff auf Form1 zu ermöglichen?

Auf globale Instanz - Variable Form1 zugreifen?
Jeder ausgelagerten Prozedur/ Methode Form1 als Parameter übergeben?
Ausgelagerte Methoden in Klasse zusammenfassen und in deren Constructor Form1 einer Feldvariablen (z.B. 'FMainform') zuweisen?
Windows-Messages?
Oder was ganz anderes?

Was käme da als halbwegs saubere Lösung in Frage? (außer alles in die Tonne kloppen und von vorne anfangen) :(

Gruß LP

TurboMagic 28. Apr 2019 15:39

AW: Trennung von GUI und Logik
 
Hallo,

spendiere doch deiner Main Form für alle diese Fortschrittsanzeigen und Ausgabebedarfe entsprechende Methoden,
welche die GUI controls aktualisieren. Diese Methoden bekommen die auszugebenden Daten als Parameter übergeben.

Dann erstelle eine neue Unit und erstelle ein Interface, welches genau diese Methodendeklarationen enthält.
Das Hauptformular nutzt diese Unit im interface uses block und in class(TForm) wird das Interface ergänzt:
class(TForm, IMainFormInterface).

Die Geschäftslogikklasse bekommt mittels Constructor dieses Interface übergeben und speichert sich das lokal ab:

constructor TBusinessLogic.Create(MainFormInterface: IMainFormInterface);
begin
inherited Create;

FMainFormInterface := MainFormInterface;
end;

Überall wo die geschäftslogik etwas auf dem GUI ausgeben muss, ruft sie die entsprechende Methode über das Interface auf:

FMainFormInterface .DisplayProgress(50); // 50% Fortschritt...

Dadurch hängt die Geschäftslogik nur noch von dem Interface ab und nicht mehr vom GUI und damit nicht mehr von internen
Änderungen des GUI.

Neumann 28. Apr 2019 15:49

AW: Trennung von GUI und Logik
 
Der 'Button1click' macht nur etwas mit der GUI. Den würde ich nicht woanders hin auslagern. Wenn man die Liste noch sonst noch braucht, könnte man diese als Stringlist z.B. in einem Datenmodul definieren.

So wie der Code aussieht, würde wohl nur das Endergebnis für den User sichtbar werden, die Zwischenergebnisse sieht man so wohl nicht.

Maekkelrajter 28. Apr 2019 16:33

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von Neumann (Beitrag 1431229)
Der 'Button1click' macht nur etwas mit der GUI.

Das Beispiel soll nur das Problem verdeutlichen. In der tatsächlichen Implementierung umfasst der Code des Handlers 82 Zeilen, verwendet das iTunes COM-Interface und enthält 13 Zugriffe auf das GUI. Das macht vielleicht auch deutlich, warum das unbedingt geändert werden soll.

Der von Turbomagic skizzierte Weg scheint mir sehr vielversprechend. So etwas schwebte mir auch vor, nur hatte ich keinen Schimmer, wie das zu realisieren wäre. Interfaces kenne ich nur dem Namen nach, sie werden ja auch vom iTunes COM-Interface verwendet, aber da ist ja schon alles fertig in der iTunes Typelibrary vorhanden.

Gruß LP

hum4n0id3 29. Apr 2019 06:24

AW: Trennung von GUI und Logik
 
Ich bin in Delphi/Lazarus selbst ein Anfänger, weil ich nur hin und wieder etwas damit mache. Hauptsächlich arbeite ich mit PHP und mache dort OOP. Deshalb vielleicht den "Ratschlag" nicht so ganz ernst nehmen. Aber ich mache es so.

1. Ich erstelle eine Unit mit Klasse-Name-XXX. Das enthält meist die Logik für meine Software. ZB.:

Delphi-Quellcode:
unit UDesktopFile;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil;

type
  TDesktopFile = class
    private

    public
      function GetAllFiles() : TStringList;

  end;

implementation

function TDesktopFile.GetAllFiles(): TStringList;
var
  StrList: TStringList;
  pathToFiles: String;
begin
  pathToFiles := GetUserDir + '/.local/share/applications/';
  StrList := TStringList.Create;

  FindAllFiles(StrList, pathToFiles, '*.desktop');
  GetAllFiles := StrList;
end;

end.
2. Ich verwende die Unit in meinem Hauptformular, oder einem anderem Formular, mit den Componenten im Formular.

Delphi-Quellcode:
procedure TFrmMainWindow.FormCreate(Sender: TObject);
var
  DesktopFile: TDesktopFile;
begin
  DesktopFile := TDesktopFile.Create;

  try
    LbDesktopFiles.Items.Assign(DesktopFile.GetAllFiles);
  finally
    DesktopFile.Free;
  end;

end;
Das ist jetzt kein Delphi, sondern Lazarus aber funktioniert für mich gut. Aber ob es so richtig ist und so gemacht wird, weiß ich nicht :lol:
Jedenfalls sind meine Formulare dadurch sauberer, bzw. übersichtlicher und für Änderungen muss ich die entsprechenden Units besuchen.

MfG

haentschman 29. Apr 2019 07:48

AW: Trennung von GUI und Logik
 
Moin...:P
Ich bin für folgendes:

1. Trennung in die Form und die Logic (seperate Units)
2. Die Eventhandlandler gehören in die Form.
3. Die GUI Sachen gehören in die Form.
4. Die Logic kennt die Form nicht! :warn: ...auch kein Interface. :zwinker:
5. Die Form gibt im Eventhandler den "Befehl" an die Logic. "
6. Die Logic holt die Daten und übergibt sie an ein selbst erstelltes Event oder gibt die Daten an das Funktionsresult zurück.
7. Mit Event: Die Form hat den Eventhandler der Logic implementiert und übergibt die Daten an die GUI.
...fertsch.
PS: Der Kreativität sind keine Grenzen gesetzt. :zwinker:



Delphi-Quellcode:
constructor TBusinessLogic.Create(MainFormInterface: IMainFormInterface);
Das mit dem Interface halte ich für gewagt. Wenn sich an dem GUI Interface was ändert, mußt du auch immer an die Logik dran...Das zu verhindern ist ja der Sinn der Trennung von GUI Und Logik. :zwinker:

PS: Ausnahmen bestätigen die Regel...

hoika 29. Apr 2019 08:55

AW: Trennung von GUI und Logik
 
Hallo,

Delphi-Quellcode:
[B]class [/B]function GetAllFiles() : TStringList;
Dann musst Du die Klasse im Formular nicht mal erstellen,
sondern per
Delphi-Quellcode:
LbDesktopFiles.Items.Assign([B]T[/B]DesktopFile.GetAllFiles);
aufrufen.

Wobei ich mir nicht sicher bin,
ob die hier einen memory leak erzeugst.
Das Assign kopiert den Inhalt der TStringList.

Ich bin immer dafür, dass der der ein Objekt erzeugt,
auch für dessen Freigabe verantwortlich ist.
Das Formular würde also die StringList erzeugen, an die GetAllFiles als Parameter übergeben,
und wenn es die StringList nicht mehr braucht, wieder freigeben.

Jumpy 29. Apr 2019 09:19

AW: Trennung von GUI und Logik
 
Das ganze Thema schreit für mich aber auch nach 'Threads'. Dementsprechend sollte vielleicht solche Dinge in eigene Threads ausgelagert werden, die dann auch nur periodisch die GUI aktualiesieren und nicht ständig.

stahli 29. Apr 2019 11:17

AW: Trennung von GUI und Logik
 
Man muss hier m.E. drei Dinge separat betrachten...


1) Trennung GUI/BL:

Dazu reicht es aus, sämtliche Logik in eine Klasse TMyBL zu stecken und dort so viele Eigenschaften und Methoden zu veröffentlichen, dass die GUI sich dort umfassend bedienen kann.
Die GUI darf also nie z.B. einen Kontostand erhöhen, indem sie den aktuellen Wert abruft, einen Betrag dazu rechnet und das Ergebnis wieder speichert, sondern sie muss TMyBL.AddMoney(x) aufrufen.
ALLES was an Daten zu ändern oder abzufragen ist, muss über Methoden und Eigenschaften möglich sein.
TMyBL muss also in sich das vollständige Projekt abbilden und komplett funktionsfähig sein.
Natürlich ist TMyBL hilflos ohne Ansteuerung von außen, aber alle Erfordernisse müssen dort vorhanden und nutzbar sein.
Die GUI (Egal ob VCL, FMX oder anderes) stößt dann lediglich Aktionen an und ruft Daten ab für die eigene Darstellung.

Wenn man mit Interfaces umgehen kann ist das sicherlich hilfreich, aber ein klassisches TMyBL-Objekt würde auch reichen.

Eine Trennung von GUI und BL wäre damit schon erreicht.


2) Threads:

Egal, ob eine längere Berechnung im Eventhandler des Formulars erfolgt oder in der oben beschriebenen TMyBL-Klasse, das Formular wird während dieser Zeit hängen bleiben.
Um das zu vermeiden, muss man mit Threads arbeiten oder notfalls mit Timern oder gar Application.ProcessMessages.
Hier ist zu beachten, dass die TMyBL davon nicht abhängig sein darf. Am besten sollte sie davon gar nichts mitbekommen.


3) Kommunikation

Vor allem, wenn GUI und BL in getrennten Threads oder gar Prozessen laufen, muss man sich über die Kommunikation Gedanken machen.
Die GUI darf die BL kennen und dort Änderungen anschieben aber sie sollte gar nicht wissen, was sie da eigentlich tut und warum.
Die BL sollte aber gar nichts von der GUI wissen.
Es muss aber einen abstrakten Informationsaustausch geben, also am besten über einen Framework, das zwischen beiden Seiten (möglichst automatisiert) vermittelt.
Die Frage ist, wie man das am besten organisiert (je nach Anspruch und Möglichkeiten).

hum4n0id3 29. Apr 2019 12:19

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von hoika (Beitrag 1431252)
Hallo,

Delphi-Quellcode:
[B]class [/B]function GetAllFiles() : TStringList;
Dann musst Du die Klasse im Formular nicht mal erstellen,
sondern per
Delphi-Quellcode:
LbDesktopFiles.Items.Assign([B]T[/B]DesktopFile.GetAllFiles);
aufrufen.

Wobei ich mir nicht sicher bin,
ob die hier einen memory leak erzeugst.
Das Assign kopiert den Inhalt der TStringList.

Ich bin immer dafür, dass der der ein Objekt erzeugt,
auch für dessen Freigabe verantwortlich ist.
Das Formular würde also die StringList erzeugen, an die GetAllFiles als Parameter übergeben,
und wenn es die StringList nicht mehr braucht, wieder freigeben.

Na wunderbar! Danke für das Kommentar :)
Und ich denke auch das ich ein Memory Leak erzeuge, jedenfalls nach meinem bisherigem Verständnis. Das TStringList, nach meinem Verständnis, wird nicht (sauber) geleert. Vermutlich nur das DesktopFile. Meine bisherigen Bemühungen schlugen aber bisher Fehl. Aber dafür mache ich mal bei Gelegenheit einen eigenen Thread auf.

Danke! Wieder was gelernt! Tolles Forum.

MfG

Gausi 29. Apr 2019 12:44

AW: Trennung von GUI und Logik
 
Warum der Umweg über eine separate StringList mit Assign? Man kann der Datenklasse doch auch direkt das Memo (bzw. dessen Property Strings) übergeben.

Delphi-Quellcode:
type

  TData = class
    public
        procedure FillList(aStrings: tStrings);
  end;

  TForm2 = class(TForm)
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
  private
    { Private-Deklarationen }
    aData: TData;
  public
    { Public-Deklarationen }
  end;



var
  Form2: TForm2;

implementation

{$R *.dfm}

{ TData }

procedure TData.FillList(aStrings: tStrings);
begin
    aStrings.Add('eins');
    aStrings.Add('zwei');
    aStrings.Add('drei');
    aStrings.Add('vier');
    aStrings.Add('fünf');
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
    aData := TData.Create;
    aData.FillList(Memo1.Lines);
end;
Funktioniert wunderbar, und man kann die Methode FillList auch für andere Zwecke nutzen, wenn man z.B. die Daten nicht in einem Memo haben will.

Für Fortschrittsanzeigen etc. könnte man z.B. mit Messages arbeiten (der Datenklasse übergibt man dann einmalig das Handle der MainForm, die die Nachrichten dann abarbeitet), oder man erstellt eigene Events mit passenden EventHandlern. Dann hat man im Code der Datenklasse regelmäßig etwas wie
Delphi-Quellcode:
if assigned(fOnProgress) then
    fOnProgress(param1, param2, param3, ...);
wobei fOnProgress eine Variable vom Typ Procedure( parameterliste ) of Object ist, die in der MainForm implementiert ist und entsprechend zugewiesen wird.

generic 30. Apr 2019 06:58

AW: Trennung von GUI und Logik
 
Na dann ergänze ich mal paar Ideen. Wirkt gerade alles sehr kompliziert.

Wo wir uns einige sind:
Die Logik darf das Oberfläche nicht kennen und muss somit auch ohne Funktionieren.
Die Oberfläche interessiert sich aber für neue und geänderte Daten, damit diese ggf. Dargestellt werden können.
Die Geschäftsobjekte sollte es nun an einer Stelle im Quelltext geben. "single point of truth"

Daher werfe ich mal eine DIY Lösung ein, welche mit Ereignissen arbeitet, welche die Logik zur Verfügung stellt.
Der klassischen Ansatz "Observer Pattern".
Vielleicht auch das "Publisher-Subscriber Pattern".

Siehe auch:
https://github.com/spinettaro/delphi-event-bus
https://www.danielespinetti.it/2017/...-and-mvvm.html

p80286 30. Apr 2019 10:20

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von generic (Beitrag 1431324)
Die Logik darf das Oberfläche nicht kennen und muss somit auch ohne Funktionieren.

"ohne" übersetz ich mal mit "beliebig (Minimal)".
Dazu dann eine dumme(?) Frage:
Gegeben sei eine Logik die mit Hilfe von Threads irgendwelche Daten bearbeitet.Innerhalb des Treads wird regelmäßig ein Postmessage mit dem aktuellen Stand der Bearbeitung abgesetzt.
Was passiert, wenn die GUI diese Messages nicht kennt?

Gruß
K-H

haentschman 30. Apr 2019 10:32

AW: Trennung von GUI und Logik
 
Zitat:

Was passiert, wenn die GUI diese Messages nicht kennt?
Die Messages die der Thread (der in der Logik erzeugt wird) sendet, kommen in der Logik an. Die Logik macht ein Event draus, was die GUI versteht. Die Logik sollte dann auch der Puffer sein, wenn die Aktualisierungen zu schnell kommen und die GUI die einfach nicht darstellen kann. :thumb: ...fertsch.
Zitat:

"ohne" übersetz ich mal mit "beliebig (Minimal)".
"ohne" heißt "ohne". Imho darf die Logik die GUI nicht kennen. Beispiel: Wenn in der Logik Daten verarbeitet werden und schon in der Logik "Rücksicht" auf die Darstellung genommen wird stellen sich mir die Nägel hoch...:lol:

DeddyH 30. Apr 2019 11:06

AW: Trennung von GUI und Logik
 
Seitdem ich viel mit Angular und RxJS mache weiß ich die Eleganz des Observer-Patterns erst richtig zu schätzen. Allerdings ist dort die GUI auch threadsafe, da müsste man in Delphi halt etwas aufpassen, machbar ist das aber auch.

TurboMagic 1. Mai 2019 08:32

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von hum4n0id3 (Beitrag 1431267)
Na wunderbar! Danke für das Kommentar :)
Und ich denke auch das ich ein Memory Leak erzeuge, jedenfalls nach meinem bisherigem Verständnis. Das TStringList, nach meinem Verständnis, wird nicht (sauber) geleert. Vermutlich nur das DesktopFile. Meine bisherigen Bemühungen schlugen aber bisher Fehl. Aber dafür mache ich mal bei Gelegenheit einen eigenen Thread auf.

Danke! Wieder was gelernt! Tolles Forum.

MfG

Ob es wirklich ein memory Leak ist seht ihr nicht, wenn das grüne Licht an geht, sondern wenn ihr in die dpr des Projektes
als erste Anweisung nach dem begin das hier reinschreibt:

ShowMemoryLeaksOnSHutdown := true;

Dann Programm ausführen, die entsprechende Aktion aufrufen und Programm beenden. Kommt keine Meldungsbox beim Beeenden
gibt's kein leak, kommt eine ist eines vorhanden.

Maekkelrajter 1. Mai 2019 15:17

AW: Trennung von GUI und Logik
 
Hallo,

seit ein paar Tagen bin ich nun dabei, die hier vorgeschlagenen Methoden der Kommunikation zwischen GUI und Logik auszuprobieren. Dabei wird für mich immer deutlicher, dass eine absolute Trennung garnicht möglich ist, wenn die Logik während der Abarbeitung des Auftrages, der vom GUI erteilt wurde, Informationen an das GUI übermitteln bzw. Aktionen des GUI auslösen soll. Die absolute Trennung funktioniert doch eigentlich nur, wenn ausschließlich der Rückgabewert einer Funktion ausgewertet werden soll.
Denn sowohl beim Absetzen von Windows-Messages als auch beim Feuern von Events muss die Logik doch wissen, wohin 'gezielt' werden soll, um eine bestimmte Aktion des GUI auszulösen. Wie soll das gehen, wenn Logik und GUI überhaupt nichts voneinander 'wissen'?
Hier meine Implementierung eines Update - Events, das tadellos funktioniert.

Die Deklaration in der Logik-Klasse sieht folgendermaßen aus:

Delphi-Quellcode:
type

TUpdateGUIEvent = procedure(Sender: TObject; index:Integer; s: string) of Object;


TGlExLogic = Class
  private
    FUpdateGUI : TUpdateGUIEvent;
    Procedure UpdateGUI(Index:Integer; s: string);
    [...]
  public
    property OnUpdateGUI: TUpdateGUIEvent read FUpdateGUI write FUpdateGUI;
End;
So wird das Event in der Logik-Klasse ausgelöst:

Delphi-Quellcode:
Procedure TGlExLogic.UpdateGUI(Index:Integer; s :string);
begin
  If Assigned(FUpdateGUI) then
  begin
     FUpdateGUI(Self, Index, s);
  end;
end;
Die Implementierung im GUI sieht dann so aus:

Delphi-Quellcode:

procedure TGL4Mainform.FormCreate(Sender: TObject);
begin
   GLMainLogic := TGlExLogic.create(self);
   GlMainLogic.OnUpdateGUI := UpDateGUI;
end;

Procedure TGL4Mainform.UpdateGUI(sender:TObject; Index:Integer; s :string);
begin
  case index of
     1: Memo1.Lines.Add(s);
     2: Memo2.Lines.Add(s);
     8: label8.caption := s;
      [...] usw.
  end;
end;
Die Logik muss doch z. B.wissen, welche Parameter mitgegeben werden müssen, um bei einem bestimmten Control der Mainform ein Update auszuführen?! Es ist dann aber auch nie auszuschließen, das bei Änderung des GUI das eine oder andere nicht mehr funktioniert.
Da wird man wohl notgedrungen Kompromisse machen und von der reinen Lehre der OOP abweichen müssen. Oder habe ich da irgendwas nicht verstanden? :?

Gruß LP

PS: Die oder Das GUI? Nach den geltenden Regeln heißt es doch im Deutschen das Interface? Oder doch nicht??

Klaus01 1. Mai 2019 17:02

AW: Trennung von GUI und Logik
 
.. die Oberfläche muss doch wissen, welches Element es updaten muss.
Das hat nicht zwingend etwas mit dem Wissen der Businesslogik zu tun.
Wie das Ergebnis zustande kam, welches die Oberfläche aktualisieren muss
darüber weiß die Oberfläche nichts.

Ich weiß nicht, ob es nicht vielleicht sinnvoller wäre ein Ereignis pro GUI Element
zu haben?

Grüße
Klaus

DeddyH 1. Mai 2019 17:11

AW: Trennung von GUI und Logik
 
Die Logikschicht muss oder gar darf von der Oberfläche nichts wissen. Im Übrigen kann es ihr ja auch egal sein, ob ein String jetzt in einem Label, einem Edit oder als ListBox-Item dargestellt wird. Sie stellt einfach nur Ereignisse zur Verfügung, an die sich die Darstellungsschicht einklinken kann oder auch nicht.

p80286 1. Mai 2019 17:22

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von haentschman (Beitrag 1431343)
Zitat:

Was passiert, wenn die GUI diese Messages nicht kennt?
Die Messages die der Thread (der in der Logik erzeugt wird) sendet, kommen in der Logik an. Die Logik macht ein Event draus, was die GUI versteht. Die Logik sollte dann auch der Puffer sein, wenn die Aktualisierungen zu schnell kommen und die GUI die einfach nicht darstellen kann. :thumb: ...fertsch.

Zitat:

Zitat von DeddyH (Beitrag 1431413)
Die Logikschicht muss oder gar darf von der Oberfläche nichts wissen. Im Übrigen kann es ihr ja auch egal sein, ob ein String jetzt in einem Label, einem Edit oder als ListBox-Item dargestellt wird. Sie stellt einfach nur Ereignisse zur Verfügung, an die sich die Darstellungsschicht einklinken kann oder auch nicht.

:wiejetzt:
Muß die Logik sich darum kümmern was aus ihren Messages wird oder nicht?

Gruß
K-H

DeddyH 1. Mai 2019 17:43

AW: Trennung von GUI und Logik
 
Wieso sollte sie? Die Darstellung muss die Logik kennen, aber nicht umgekehrt.

stahli 1. Mai 2019 18:17

AW: Trennung von GUI und Logik
 
Zitat:

Zitat von Maekkelrajter (Beitrag 1431410)
Hallo,

seit ein paar Tagen bin ich nun dabei, die hier vorgeschlagenen Methoden der Kommunikation zwischen GUI und Logik auszuprobieren. Dabei wird für mich immer deutlicher, dass eine absolute Trennung garnicht möglich ist, wenn die Logik während der Abarbeitung des Auftrages, der vom GUI erteilt wurde, Informationen an das GUI übermitteln bzw. Aktionen des GUI auslösen soll....

PS: Die oder Das GUI? Nach den geltenden Regeln heißt es doch im Deutschen das Interface? Oder doch nicht??

Delphi bietet eben keine interne Lösung, um eine Zwei-Wege-Datenbindung zu ermöglichen (abgesehen von den Livebindings :? ).

Möglichkeiten, so etwas zu programmieren gibt es mehrere. Mir gefällt es aber nicht, irgendwelche Methoden händisch zu schreiben, die den Austausch abwickeln.

Statt dessen wünsche ich mir ein Framework, dass das abstrakt im Hintergrund erledigt.
Z.B. habe ich in der BL Personen in einer Liste "Familie".
Dann will in der GUI (für mich: "DIE Schnittstelle") eine Listbox binden an "Familie" und dort einstellen, dass die Items die Eigenschaft "Vorname" verwenden sollen (natürlich etwas verkürzt dargestellt).
Jetzt soll die Liste
Zitat:

Karl
Hilda
Phillip
anzeigen.
Ist in der Listbox oder der Liste keine Sperre eingestellt, muss diese auch bearbeitet werden können (ähnlich DBControls).

Dazu müssen BL und GUI sich austauschen können, ohne dass beide sich wirklich kennen.
Es muss eine Kommunikationsschnittstelle geben, die mit beiden Seiten klar kommt, ohne selbst wieder etwas von BL und GUI zu kennen. Sie muss also sehr abstrakt arbeiten.

Ich habe mich mal an einem Framework versucht: https://www.delphipraxis.net/173360-...framework.html
Du kannst ja mal etwas stöbern. Aus meiner Sicht war der Ansatz schon sehr gelungen.

Das Projekt habe ich aber eingestellt und arbeite an etwas neuem (was noch länger dauern wird, wovon ich aber die grundsätzliche Funktionalität schon mal festgestellt habe).

Chemiker 1. Mai 2019 22:19

AW: Trennung von GUI und Logik
 
Hallo,

https://www.bing.com/videos/search?q...1&&FORM=VDRVRV

Vielleicht hilft das Video weiter.

Bis bald Chemiker

Rollo62 2. Mai 2019 05:29

AW: Trennung von GUI und Logik
 
Oder das hier.

haentschman 2. Mai 2019 06:18

AW: Trennung von GUI und Logik
 
Moin...8-)
Zitat:

Die oder Das GUI?
... "die" :stupid: https://de.wikipedia.org/wiki/Grafis...berfl%C3%A4che
Zitat:

Hier meine Implementierung eines Update - Events, das tadellos funktioniert.
...das ist der Standard für ein Event für den Austausch von Daten an die GUI. :wink:
Zitat:

Ich weiß nicht, ob es nicht vielleicht sinnvoller wäre ein Ereignis pro GUI Element
zu haben?
...eher nicht. Mache ein Event für eine "Aufgabe" ("Laden des Auftrages" z.B.). Für die Aktualisierung einer Progressbar ("Zeige Status Auftrag") hast du ein Event für ein Control.


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