Autor Beitrag
LittleBen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 17.10.13 20:50 
Hallo,
in der Schule behandeln wir zurzeit das Thema 3-Schichtenmodell in Java, also GUI,Steuerung und Daten.
Jetzt meine Frage: ist das Java-Spezifisch oder handhabt man das in Delphi auch so? Hab meine Projekte bis jetzt immer komplett anders gestaltet...halte es aber für eine gute Idee.
Und noch eine frage: Wie löst man die Kommunikation zwischen den verschiedenen Schichten? Ich würde es, um den Code noch mehr zu verallgemeinern, alles mit Events machen. Also die GUI kennt die Steuerung, aber die Steuerung nicht die GUI. Die Steuerung löst nur Events aus, die beim Kreieren mitgehlieft wurden. Die GUI reagiert dann darauf. Wie löst man das professionel, nach der alten delphischen Art?

Viele Grüße
Littleben
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 17.10.13 21:46 
Das macht man in Delphi ähnlich. Ob nun GUI, Steuerung und Daten die beste Aufteilung ist, sei dahingestellt, aber prinzipiell eine Abtrennung mindestens der GUI ist immer sinnvoll.

Ich halte in Delphi Interfaces für am sinnvollsten. Mit Events programmierst du dich eher tot. Mit Interfaces registrieren sich die einzelnen Teile gegenseitig und fertig.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 17.10.13 22:10 
Mhm, wie würde das mit den Interface dann in etwas aussehen?
Angenommen man macht die GUI und Steuerung in eine Klasse (nur zur Übersichtlichkeit):
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
unit Unit1;

interface

uses
  {...}

type
  TMyControl = class
  private
    procedure DownloadSomeData;
  public
    { Public-Deklarationen }
  end;

type
  TMyGUI = class(TForm)
  private
    FMyControl: TMyControl;
  public
    { Public-Deklarationen }
  end;

var
  GUI: TGUI;

implementation

{$R *.dfm}

end.

Wie würdest du hier die Kommunikation gestalten, wenn die GUI die Methode DownloadSomeData aus dem MyControl-Objekt aufruft, und dieses dann die Daten auf die GUI schreiben soll (kein Thread, und auch keine Rückgabewert ;) ).
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 17.10.13 23:22 
Ein vollständiges Beispiel, nicht sonderlich schön, aber es sollte das Prinzip zeigen:
ausblenden volle Höhe Hauptprogramm
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
program Project17;

uses
  Vcl.Forms,
  System.Generics.Collections,
  Unit9 in 'Unit9.pas' {Form9};

{$R *.res}

type
  TAppController = class(TInterfacedObject, IAppController)
  private
    var
      FGUIList: TList<IMyGUI>;
  public
    constructor Create;
    destructor Destroy; override;
    procedure RegisterGUI(const AGUI: IMyGUI);
    procedure UnregisterGUI(const AGUI: IMyGUI);
    procedure DisplayText(const AValue: string);
    procedure TextEntered(const AValue: WideString);
  end;

{ TAppController }

constructor TAppController.Create;
begin
  FGUIList := TList<IMyGUI>.Create;
end;

destructor TAppController.Destroy;
begin
  FGUIList.Free;
  inherited;
end;

procedure TAppController.DisplayText(const AValue: string);
var
  CurrentGUI: IMyGUI;
begin
  for CurrentGUI in FGUIList do
    CurrentGUI.DisplayText(AValue);
end;

procedure TAppController.RegisterGUI(const AGUI: IMyGUI);
begin
  if not FGUIList.Contains(AGUI) then
  begin
    AGUI.RegisterController(Self);
    FGUIList.Add(AGUI);
  end;
end;

procedure TAppController.TextEntered(const AValue: WideString);
begin
  DisplayText(AValue);
end;

procedure TAppController.UnregisterGUI(const AGUI: IMyGUI);
begin
  FGUIList.Remove(AGUI);
end;

var
  MyController: IAppController;
begin
  MyController := TAppController.Create;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TForm9, Form9);
  MyController.RegisterGUI(Form9);
  Application.Run;
end.
ausblenden volle Höhe Formularunit
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
unit Unit9;

interface

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

type
  IMyGUI = interface;

  IAppController = interface
    procedure TextEntered(const AValue: WideString);
    procedure RegisterGUI(const AGUI: IMyGUI);
  end;

  IMyGUI = interface
    procedure RegisterController(const AController: IAppController);
    procedure DisplayText(const AValue: WideString);
  end;

  TForm9 = class(TForm, IMyGUI)
    Memo1: TMemo;
    Memo2: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    var
      FController: IAppController;
  protected
    procedure RegisterController(const AController: IAppController);
    procedure DisplayText(const AValue: WideString);
  end;

var
  Form9: TForm9;

implementation

{$R *.dfm}

{ TForm9 }

procedure TForm9.Button1Click(Sender: TObject);
begin
  if Assigned(FController) then
    FController.TextEntered(Memo2.Text);
end;

procedure TForm9.DisplayText(const AValue: WideString);
begin
  Memo1.Text := AValue;
end;

procedure TForm9.RegisterController(const AController: IAppController);
begin
  FController := AController;
end;

end.

In einem echten Programm gehören die Klassen und Interfaces natürlich in eigene Units usw., wie gesagt, nur ein ganz schnelles Beispiel...

Architektur:
Die GUI wird beim Controller angemeldet, der Controller meldet sich bei dieser Registrierung wiederum bei der GUI an. Dazu kann dann ebenso vom Controller aus noch der Datenteil kommen.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Fr 18.10.13 16:03 
Vielen Dank für das Beispiel!
Die Interfaces kommen dann in eine eigene Unit. Wie wird diese so standardmäßig genannt?

ausblenden Delphi-Quelltext
1:
2:
type
  IMyGUI = interface;
Ich nehme mal an, diese Zeile war ein Versehen?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Fr 18.10.13 16:15 
user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
Die Interfaces kommen dann in eine eigene Unit. Wie wird diese so standardmäßig genannt?
Zum Beispiel kannst du das in einen Unterordner Interfaces legen und die Units genauso wie die Interfaces nennen. Also Zum Beispiel Littleben.Interfaces.MyGUI für das Interface IMyGUI. Wenn du es weniger modular haben möchtest, kannst du auch die Interfaces in einer eigenen Interface-Unit zusammen lassen, aber ich finde das etwas unübersichtlich.

Bei deinem Delphi 7 weiß ich nicht, ob die Punkte im Unitnamen überall funktionieren. Das konnte das zwar schon, aber ich weiß nicht, ob überall.

Ich würde jedenfalls entweder eine Sammelunits für die Interfaces oder Units, die mit Interfaces und ggf. einem Zusatz genauso wie das Interface heißen nehmen.

user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
type
  IMyGUI = interface;
Ich nehme mal an, diese Zeile war ein Versehen?
Nein, eine forward Deklaration. Das danach folgende Interface benötigt das Interface IMyGUI, deshalb muss vorher schon einmal deklariert werden was das für ein Typ ist, nämlich ein Interface.

In deinem echten Programm sollten solche Rückwärtsreferenzen nicht nötig sein, das lag nur daran, dass das Beispiel so kompakt bleiben sollte.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 23.10.13 19:26 
Ich habe das gerade mal unter XE5 (bin jetzt auch auf dem neusten Stand :) ) mit Firemonkey auspobiert. Dort bekomme ich eine Access Violation sobald ich das Formular vor Application.Run benutze.
Wie muss ich es dann anstellen?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 23.10.13 19:34 
Naja, erstellt sein muss es. Das Hauptformular mit Application.FormCreate, die anderen direkt. Ohne Quelltext kann man dazu aber nicht viel sagen.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 23.10.13 19:44 
Ich verstehs auch nicht... hoffe nur es sind nicht wieder mal irgendwelche Tücken von Firemonkey -.-
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
// Application
var Controller: IMyControl;
begin
  Controller:= TMyControl.Create;
  Application.Initialize;
  Application.FormFactor.Orientations := [TFormOrientation.soInvertedLandscape];
  Application.CreateForm(TF_Main, F_Main);
  Controller.RegisterGUI(F_Main);
  Application.Run;
end.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
// Controller
procedure TMyControl.RegisterGUI(const aGUI: IMyGUI);
begin
 aGUI.RegisterController(Self); // Hier wird die Exception ausgelöst
 FGUI:= aGUI;
end;

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
// GUI
procedure TF_Main.RegisterController(const aController: IMyControl);
begin
 FControl:= aController;
end;


Es ist alles so, wie du es mir erklärt hast :/
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 23.10.13 22:09 
Das sieht erst einmal nicht schlecht aus. Häng am besten mal das ganze Projekt an, viel ist da ja vermutlich ohnehin noch nicht drin.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 24.10.13 12:32 
Okay, im Anhang mein Testprojekt. Muss ein saublöder Fehler sein :?!?:

Wenn ich testweise soetwas einbau:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
var Controller: IMyController;
begin
  Controller:= TMyController.Create;
  Application.Initialize;
  Application.CreateForm(TF_Main, F_Main);
  Application.Run;
  Controller.RegisterGUI(F_Main);
  Application.ProcessMessages;
  Sleep(1000);

dann funktioniert es, aber eben erst nach dem Schliesen...

EDIT: Hab das Problem gefunden gefunden... nach dem CreateForm muss noch folgendes eingefügt werden:
Application.RealCreateForms;
Dann funktionierts!
Einloggen, um Attachments anzusehen!
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 24.10.13 13:29 
Ok, das ist nur mit FireMonkey so, in der VCL wird das Formular auch direkt erzeugt, nicht erst beim Ausführen.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 24.10.13 15:19 
So ein scheeeiii.... :evil: :evil: :autsch:
Unter iOS darf ich die Forms nicht früher kreieren. Ich bekomme bei der Funktion function TPlatformCocoaTouch.CreateWindow(const AForm: TCommonCustomForm): TWindowHandle; eine Access Violation Exception bei LOrientation := UIApp.statusBarOrientation; :x
Keine Ahnung was ich jetzt tun soll :cry:
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19314
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 24.10.13 15:59 
Eine Möglichkeit, ungetestet:

ausblenden Projektquelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
var
  Controller: IMyController;
begin
  Controller:= TMyController.Create;
  TF_Main.OnCreateGUI := procedure(const AGUI: IMyGUI)
    begin
      Controller.RegisterGUI(AGUI);
    end;
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TF_Main, F_Main);
  Application.Run;
end;

ausblenden Formularunit
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
  TF_Main = class(TForm, IMyGUI)
    procedure FormCreate(Sender: TObject);
  private
    type
      TOnCreateGUI = reference to procedure(const AGUI: IMyGUI);
    class var
      FOnCreateGUI: TOnCreateGUI;
  public
    class property OnCreateGUI: TOnCreateGUI read FOnCreateGUI write FOnCreateGUI;
  end;

//...

procedure TF_Main.FormCreate(Sender: TObject);
begin
  if Assigned(FOnCreateGUI) then
    FOnCreateGUI(Self);
end;
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 24.10.13 17:33 
user profile iconjaenicke hat mal wieder zugeschlagen :!: :flehan:
Funktioniert.

Nur noch aus Interesse: Gäbe es noch eine oder mehere Möglichkeiten das Proboblem zu lösen? Hörte sich so an als wüsstest du noch andere Wege.