Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Globale Variablen und Sichtbarkeit (https://www.delphipraxis.net/190235-globale-variablen-und-sichtbarkeit.html)

Amicello 15. Sep 2016 00:20

Globale Variablen und Sichtbarkeit
 
Dephi macht mich wahnsinnig - gerade jetzt wo mein Projekt wächst. Eigentlich hatte ich geplant, alles ein wenig strukturiert in mehrere Units aufzuteilen.
Es ist ja nun mal so, dass die ganzen Programmteile auch zusammen miteinanander und untereinander agieren sollen.
Jetzt prügel ich mich schon wieder den ganzen Abend und Nacht mit Delphi Zickigkeiten und Nickeligkeiten rum, anstatt ich wirklich zum effektiven Programmieren gekommen wäre.

Eine Unit ist z.B. für das Form zuständig, eine andere für allgemeine Funktionen die ich benutze und so weiter.
Für die Programm-Settings habe ich eine eigene Klasse definiert, die Vorgaben, Einstellungen und überall benötigte Dinge bereitstellen soll.

Die OnClick Prozeduren innerhalb des Forms müssen nun natürlich auf die allgemeinen Funktionen Zugriff haben,
während ich in den allgemeinen Funktionen gern auf die Anzeigeelemente im Form zugreifen muss.
Eine Unit greift hier auf die Funktionen der anderen zu - und natürlich umgekehrt, aber die Units gegenseitig in die Uses-Blöcke einzutragen ist natürlich Käse.
Dann steht die Instanz der Form-Klasse wiederum (obwohl in der "Hauptdatei" unter Interfaces global deklariert) nicht in einer Unterunit zur Verfügung...
Eine Katze die sich mal so herum und mal andersrum in den Schwanz beisst.

Es ist zum Haareraufen. Es bleibt wohl keine andere Möglichkeit, als alles in eine einzige Datei zu klatschen, oder wie ist hier der Denkansatz?

Anders gefragt, ich möchte eine Variable/Klasse o.ä so global deklarieren, dass ich von allen Komponenten darauf zugreifen kann.
Das muss doch gehen, oder?

BUG 15. Sep 2016 00:42

AW: Globale Variablen und Sichtbarkeit
 
Das was du wirklich möchtest, sind Interfaces.

Sowohl die Unit mit den Funktionen als auch die des Formular kennen die Unit mit den Interface. Das Formular implementiert das Interface. Die allgemeinen Funktionen erwarten jeweils eine Instanz des Interfaces, um darauf Methoden aufzurufen.
Jetzt kann das Formular die Funktions-Unit kennen und Funktionen aufrufen, ohne das die Funktionen das Formular kennen müssen. Als Bonus kannst du jetzt die Formular-Implementierung austauschen (oder mehrere haben) ohne das die Funktionen das mitbekommen.

Vorher:
  • Formular -> Funktionen
  • Funktionen -> Formular

Nachher:
  • Formular -> Funktionen
  • Formular -> Interface
  • Funktionen -> Interface

Ich würde dir empfehlen, dich mal allgemeiner mit "moderner" objektorientierter Programmierung und Architektur befassen: Da könnte einiges Nützliches für dich dabei sein, was dir hilft solche Probleme von Anfang an zu umgehen.

Luckie 15. Sep 2016 01:11

AW: Globale Variablen und Sichtbarkeit
 
@Amicello:Kannst du dein Konzept vielleicht in einem Klassendiagramm verdeutlichen? Ich steige da nicht so ganz durch. Ich vermute eher deine Probleme resultieren aus einem etwas unsauberen Konzept und weniger aus den angeblichen Unzulänglichkeiten von Delphi.

Benedikt Magnus 15. Sep 2016 08:34

AW: Globale Variablen und Sichtbarkeit
 
Zitat:

Zitat von Amicello
Eine Unit greift hier auf die Funktionen der anderen zu - und natürlich umgekehrt, aber die Units gegenseitig in die Uses-Blöcke einzutragen ist natürlich Käse.

Zirkuläre Unitnutzung ist in einem Falle wie deinem durchaus angebracht. Das geht in Delphi, indem du nicht die Usesblöcke im interface-Abschnitt nutzt, sondern sie im implementation-Abschnitt einträgst. Wenn du im interface auf eine andere Unit zugreifst, dann natürlich im interface eintragen. Nur bei lediglich einer von beiden muss es im implementation-Teil sein. Zirkuläre Zugriffe im interface-Teil lassen sich aber in aller Regel vermeiden.

Delphi-Quellcode:
unit Unit1;

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)
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

uses
  Unit2, Unit3;

{$R *.dfm}

end.

Bjoerk 15. Sep 2016 10:34

AW: Globale Variablen und Sichtbarkeit
 
Du hast Logik und Darstellung ja schon getrennt. Fein. :-D

Wie wär es, wenn TMainform die Instanzen der Klassen erstellt und sie an die anderen Formulare verteilt. Am besten gleich über den Konstruktor, (die automatische Erzeugung dieser Formulare dann aus den Projektoptionen heraus nehmen).

Beispiel:

Delphi-Quellcode:
procedure TMainForm.FormCreate(Sender: TObject);
begin
  FSomeClass := TSomeClass.Create;
  Form2 := TForm2.Create(Self, FSomeClass);
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  FSomeClass.Free;
end;
In TForm2 überschreiben wir den Konstruktor der Form:
Delphi-Quellcode:
type
  TForm2 = class(TForm)
  private
    FSomeClass: TSomeClass;
  public
    constructor Create(AOwner: TComponent; const Value: TSomeClass); reintroduce; overload;
  end;

var
  Form2: TForm2;

implementation

{$R *.DFM}

constructor TForm2.Create(AOwner: TComponent; const Value: TSomeClass);
begin
  inherited Create(AOwner);
  FSomeClass := Value;
end;

bcvs 15. Sep 2016 11:06

AW: Globale Variablen und Sichtbarkeit
 
Zitat:

Zitat von Amicello (Beitrag 1347694)
Die OnClick Prozeduren innerhalb des Forms müssen nun natürlich auf die allgemeinen Funktionen Zugriff haben,
während ich in den allgemeinen Funktionen gern auf die Anzeigeelemente im Form zugreifen muss.

Wenn die "allgemeinen Funktionen" Zugriff auf die Anzeigeelemente der Form brauchen, sind sie nicht mehr allgemein, dann brauchst du sie auch nicht in eine separate Unit auszulagern.

Wenn allerdings in den allgemeinen Funktionen wiederum zu viel Programmlogik steckt, die du von der Oberfläche getrennt haben willst, kannst du auch der Funktion z.B. den Inhalt des Controls übergeben, oder was sie halt braucht. Oder du übergibst der Funktion gleich das Control als Parameter, dann muss sie die Form auch nicht kennen.

jaenicke 15. Sep 2016 11:22

AW: Globale Variablen und Sichtbarkeit
 
Zitat:

Zitat von Benedikt Magnus (Beitrag 1347707)
Zirkuläre Unitnutzung ist in einem Falle wie deinem durchaus angebracht.

Möglich ist das sicher, aber angebracht oder sinnvoll nicht. Denn dadurch verzahnt man Code miteinander viel zu sehr. Dadurch ist er dann kaum testbar oder wartbar.
Denn wie willst du Code sinnvoll testen, der nicht eine Eingabe bekommt und ein Ergebnis liefert, sondern der auf einer GUI etwas mit einem Control macht?
(Klar muss man auch so etwas testen, aber das ist dann nicht die Businesslogik, sondern die GUI-Logik.)

Wie es sauber geht hat BUG ja oben schon geschrieben, mit Interfaces.

stahli 15. Sep 2016 11:39

AW: Globale Variablen und Sichtbarkeit
 
Mit "allgemeinen Funktionen" meinst Du "Businesslogic"?

Es ist immer gut, eine solche Trennung von GUI und BL vorzunehmen.
In dem Fall sollte die BL aber auch nichts von Deinem Formular wissen - auch nichts von Controls.

Statt BL.AddiereZuKonto(Edit) und dort Edit.Text zu interpretieren solltes Du direkt den Wert übergeben.

Mit einem Databinding-Framework kann man es sich noch einfacher machen. Hier muss man sich letztlich fast nur um die Logik kümmern und bindet ein Control dann einfach an ein bestimmtes Feld. Leider sind die LiveBindings (soweit ich das einschätzen kann) nicht wirklich sehr tauglich.

Dann muss man es halt von Hand regeln, aber möglichst ohne Controls in die BL zu übergeben.


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