Deklaration von Variablen

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Deklaration von Variablen

Beitrag von Albin »

Moin liebe Forenmitglieder,

ich habe eine kleine Testapplikation, fürs erste mit einer GUI-Form ich nenn sie mal "Main-Form", also das Standardding, das vom IDE erzeugt wird. Ein kleiner Timer mit einem Button "Start/Stop", je nachdem ob der Timer läuft oder nicht, wird er mit dem gestartet oder gestoppt. Das bekommt man ja ganz gut mit Tutorials hin, deswegen habe ich mich entscheiden langsam am praktischen Beispiel voranzuhangeln, bevor ich anfange erst ewig Bücher mit Grundlagen zu wälzen (da kann man sich sicher über die Sinnhaftigkeit streiten).

Jetzt bin ich auf ein bisschen Erfahrung angewiesen, denn jetzt möchte eine Abstraktionstufe erstellen und GUI und Funktionalität von einander kapseln. Spich die reguläre Procedur "Button1Click" soll sich nur noch um die GUI Operationen kümmern (Farbe des Knopfs ändern etc.) die eigentliche Funktionalität möchte ich unabhängig verwalten, also Startzeit, Endzeit, Zusätzliche binäre Flag ob der Timer läuft etc.

Meine jetztiger (einfacher) Plan sieht so aus, dass ich die Unit, in der auch die Main-Form steckt, mit Globlen Konstanten/Varialen sowie Prozeduren für StopTimer, StartTimer etc. versehe um möglichst wenig zusätzliche Overhead zu erzeugen. Hierzu hab ich schon mal eine zusätzliche Prozedur (procedure TimerStarten) in der GUI-Form Unit (zw. "implementation" und den Prozeduren der Objekte auf der Form) erstellt, die beim Buttonclick aufgerufen wird. Weil ich die Variabeln in meiner Unwissenheit im Publicteil der Form deklariert habe, muss ich sie in meiner neuen Prozedur mit form1.variableXY bezeichnen, das ist finde ich unschön.

Daher meine erste Frage:
Wohin kann ich die Variabendeklaration erstmal irgendwohin verschieben, damit sie von den GUI-Elemten-Prozeduren als auch von meiner mit der gleichen Bezeichnung aufgerufen werden können? Oder kann ich die Prozedur irgendwie entsprechend deklarieren? Da gibts sicher mehrere Möglichkeiten, die einen mit mehr, die anderen mit weniger Overhead, mich interessiert erstmal die "einfachste" Möglichkeit (vgl. Frage 2). Am "schönsten" wäre natürlich, ich kann sie irgendwo/wie in der Unit entsprechend deklarieren, aber da ich das nicht finden konnte, wirds wohl auch nicht gehen, entspricht ja auch nicht dem OO-Konzept.

Meine zweite Frage:
Wenn ich das ganze in einem zweiten Schritt wirklich sauber machen möchte, wäre es sinnvoller die Funktions-Prozeduren in einer eigenen Klassen z.B. "Timer" zu definieren? Insbesondere im Hinblick auf weiteres Wachstum des Programms z.B. Verwendung von unterschiedlichen Forms, die auf diese Funktions-Prozedur zugreifen etc.? Sollte ich das dann auch in eine eigene Unit schreiben? Vermutlich gibts hier auch wieder mehrer Möglichkeiten mit jeweiligen Vor/Nachteilen...

Zu meinem Hintergrund: Ich hab zwar grundsätzlich Ahnung von Programmierung, hab aber ausser diversen Skriptsprachen schon ewig nicht mehr programmiert, würde mich über ein bisschen "Sänfte" freuen ;)

Danke, Albin

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

Also die erste Frage konnte ich mir inzwischen selber beantworten. Hab es als Prozedur in der Klassendefinition der Form declariert und mit dann mit Form1.TimerProcedureXY aufgerufen. Erfüllt also das was ich braucht. Bleibt noch Frage Zwei: ist meine Implementation sinnvoll, oder würdet Ihr was anderes wählen z.B. die TimerProceduren über eine eigenen TimerClasse implementieren. Und falls das der Fall ist, macht es Sinn, für diese Klasse eine eigene Unit zu erstellen oder soll ich sie auch in der MainForm-Unit erstellen?

Vielen Dank!

Thandor
Beiträge: 153
Registriert: Sa 30. Jan 2010, 18:17
OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 3.0 mit FPC 3.2.2 (32Bit + 64bit)
CPU-Target: 64Bit
Wohnort: Berlin

Re: Deklaration von Variablen

Beitrag von Thandor »

Hallo für das trennen von GUI und Fachlogik könnte mann das Fasaden-Pattern anwenden. Eine Fassade ist eine Klasse, die die GUI und die Fachlogik kennt. Die Fachlogik ist auch eine oder mehre Klassen. Wenn die GUI einen Wert in der Fachlogikm ändern möchte, muss die GUI dies der Fasade mitteilen und die Fasade leitet den Befehl weiter.

Du kannst aber auch die Fassade weglassen und die GUI direkt auf die Methoden deiner Fachlogik-Klasse zugreifen lassen.

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

Danke, ich habs mal kurz überflogen: https://de.wikipedia.org/wiki/Fassade_(Entwurfsmuster)
Demnach würd ich die Timer-Funktionalität/en in eigenen Klasse/n impelmentieren, die ich dem GUI wiederum über eine Fassaden-Klasse zugänglich mache... hmmm, ok, würde sinn machen wenn ich viele Funktionsklassen hätte, aber beim Timer werden die wohl überschaubar sein. Daher würde ich jetzt die Entscheidung treffen die Timer-Funktinalität in eigene Klassen auszulagern welche ich dann über Events der GUI-Elemente direkt anspreche. Oder gibt mir das noch andere Vorteile, die ich jetzt nicht sehe?

Das Pattern entspricht ja im wesentlichen der Java-Interface-Classe, oder? (Für die Leute, die auch Java kennen)

Bleibt auch noch die Frage, ob ich für die TimerFunktionalitäts-Klassen (und ggf. die Fassadenklasse) eigene Units nehme, oder die Unit verwende in der auch die Form steckt??!

Hmmmm, das sind an dieser Stelle vielleicht keine Anfängerfrage mehr... daher noch was "Einfaches" zum Schluss:
Wenn eine Form-Klasse von Lazarus angelegt wird splittet die sich in drei Teile:
1) Hier werden alle GUI-Elemente und deren Events deklariert
2) Private-Deklarationsteil
3) Public-Deklarationsteil

Warum gibt es den ersten Teil überhaupt? Ich vermute mal die in Teil 1 deklarieten GUI-Elemnte und Prozeduren sind Private, warum werden die nicht direkt in der Private Sektion deklariert (bzw. in der Public, wenns anders rum ist). Dient das zur Trennung von automatisch und vom User angelgenten Elementen und/oder zur bessern Übersichtlichkeit? Oder gibts da andere Gründe?

Und weils grad so schön ist: Ich kann im Implementationsteil einer Unit Prozeduren anlegen, die nicht im Interfaceteil deklariert wurden. Die sind nicht nach aussen sichtbar, soweit alles klar, aber warum zum Teufel, müssen die _unbedingt_ "über" den Prozeduren stehen, die auf sie zugreifen? Eigentlich will ich meinen Code lieber so strukturieren, dass die "Hauptprozeduren" oben stehen und meine "Subprozeduren" unten, laesst sich das irgenwie lösen, indem ich sie im "oben" im Implementationsteil einfach nur einzeilig "deklariere" und dann ganz am Ende "implementiere". Ich vermute mal eine Deklaration von Prozeduren im Implementationsteil ist nicht vorgesehen, aber vielleicht gibts ja eine Möglichkeit für den Workaround.
Siehe hierzu: http://www.lazarusforum.de/viewtopic.php?f=55&t=2519 Beitrag vom 18. Mär 18:09

Danke!!! Albin

Thandor
Beiträge: 153
Registriert: Sa 30. Jan 2010, 18:17
OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 3.0 mit FPC 3.2.2 (32Bit + 64bit)
CPU-Target: 64Bit
Wohnort: Berlin

Re: Deklaration von Variablen

Beitrag von Thandor »

Zum Thema Fassade hast du, nach meiner Auffassung, alles richtig verstanden. Die Fassade hat den nach meiner Ansicht den größten Vorteil, wenn man auf einfachen Wege die GUI austauschen, austauschbar machen möchte. Deswegen habe ich ja geschriebm, dass du in deinem Fall die Fassade weg lassen kannst und die Fachlogik-Methoden direkt verwenden.

Zum Thema Funktionen im Implementation-Teil:
Schau dir dazu mal die Forward-declerations an.

Code: Alles auswählen

 
function tueetwas(a,b : Integer) : Integer; Forward;
 
// Andere Funktionen die tueetwas verwenden...
 
function tueetwas(a,b : Integer) : Integer;
begin
  // ...
end;
 

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Deklaration von Variablen

Beitrag von wp_xyz »

Albin hat geschrieben:Wenn eine Form-Klasse von Lazarus angelegt wird splittet die sich in drei Teile:
1) Hier werden alle GUI-Elemente und deren Events deklariert
2) Private-Deklarationsteil
3) Public-Deklarationsteil

Warum gibt es den ersten Teil überhaupt? Ich vermute mal die in Teil 1 deklarieten GUI-Elemnte und Prozeduren sind Private.

Nein, die Elemente in Teil 1 sind "published" (ohne dass es da steht). "Published" bedeutet, dass der Objektinspektor darauf zugreifen kann. Wenn du hier z.B. eine Prozedur ButtonClick(Sender: TObject) aufführst, dann ist sie in der Aufklappliste des Ereignisses OnClick eines Buttons im Objektinspektor zu sehen; steht sie weiter unten, unter private oder public (es gibt auch noch "protected"), ist sie im Objektinspektor nicht zu sehen.

Warf
Beiträge: 1909
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: Deklaration von Variablen

Beitrag von Warf »

Fassade ist hier denke ich das falsche Muster, was du suchst ist das Model-View-Controller Muster.
Bei diesem Muster wird die Software in 3 Schichten gegliedert, die Model-Schicht enthält die Daten und übernimmt die gesamte Logik. Eine (oder Mehrere) View-Schicht(en) übernimmt die Darstellung und das entgegennehmen der Nutzereingaben. Die View Schichten sind in etwa die Formularklassen die Lazarus erstellt. Die Control-Schicht übernimmt das Management der View Klassen, und dient als Schnittstelle zwischen Modell und View, der Controller stellt die Daten des Modells auf dem View dar, und verarbeitet die Nutzereingaben des Views.

Dieses Muster hat den Vorteil, dass du Änderungen z.B. am Design (über den View) machen kannst, ohne am Controller oder dem Modell was ändern zu müssen, da alle schichten Problemlos austauschbar sind, ohne die anderen zu beinflussen (im optimalfall)

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

@warf
genau das MVC-Model hatte ich bei meiner Fragestellung auch im Hinterkopf. Im ersten Schritt wollte ich aus meinem "ich pack einfach alles ins GUI-Event"-Stil alle Proceduren heraustrennen die eigentlich zum Controler gehören. Aber gut zu wissen, das wir auf einer Linie sind!

@wp_xyz
ah, ok, danke. So macht das natürlich Sinn. Bei mir zeigt der Objektinspector allerdings nur die Declarierten GUI-Elemente an, das auf dem Eventreiter die Events für alle GUI-Elemente einsehbar sind hab ich noch gar nicht geschnallt danke!!
@All
Gibts so einen Inspector eigentlich auch für meine gesamte Unit? Ich fänds z.B. Interessant alle Methoden aus dem Implementationsteil aufgelistet zu sehen, so dass ich einfacher Navigieren kann? Die Bookmarks scheinen ja leider auf 10 beschränkt zu sein, sonst hätte ich mir einfach für jede Procedur einen Bookmark gesetzt.

@Thandor
ok, also die Funktionen nicht direkt im Implementationsteil sondern unter der Funktion deklarieren, die sie auch verwendet. Ist nur bedingt schön weil sie auch hier wieder am Anfang stehen, vielleicht lager ich die dann einfach in andere Units aus, dann hab ich das Problem nicht mehr. Müsste doch gehen, oder? Das würde dann auch meiner Frage beantworten, wann es (beilspielsweise) Sinnvoll ist "Controler"-Prozeduren (in Anlehnung das MVC-Konzept) in einer neuen Unit zu impelemtieren.

Und Danke für Eure Hilfe, super Forum hier!! : )

wp_xyz
Beiträge: 4889
Registriert: Fr 8. Apr 2011, 09:01

Re: Deklaration von Variablen

Beitrag von wp_xyz »

Albin hat geschrieben:@All
Gibts so einen Inspector eigentlich auch für meine gesamte Unit? Ich fänds z.B. Interessant alle Methoden aus dem Implementationsteil aufgelistet zu sehen, so dass ich einfacher Navigieren kann? Die Bookmarks scheinen ja leider auf 10 beschränkt zu sein, sonst hätte ich mir einfach für jede Procedur einen Bookmark gesetzt.

CodeExplorer? ("Ansicht" > "CodeExplorer")

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

wp_xyz hat geschrieben:CodeExplorer? ("Ansicht" > "CodeExplorer")


Danke für den Hinweis (den hatte ich natürlich ausprobiert, aber per Default zeigt er nix vom Impelementationteil an :S) -> SOLVED :)

Thandor
Beiträge: 153
Registriert: Sa 30. Jan 2010, 18:17
OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 3.0 mit FPC 3.2.2 (32Bit + 64bit)
CPU-Target: 64Bit
Wohnort: Berlin

Re: Deklaration von Variablen

Beitrag von Thandor »

Albin hat geschrieben:@warf
@Thandor
ok, also die Funktionen nicht direkt im Implementationsteil sondern unter der Funktion deklarieren, die sie auch verwendet. Ist nur bedingt schön weil sie auch hier wieder am Anfang stehen, vielleicht lager ich die dann einfach in andere Units aus, dann hab ich das Problem nicht mehr. Müsste doch gehen, oder? Das würde dann auch meiner Frage beantworten, wann es (beilspielsweise) Sinnvoll ist "Controler"-Prozeduren (in Anlehnung das MVC-Konzept) in einer neuen Unit zu impelemtieren.


Ich dachte du wolltest ein ähnlichen Aufbau wie Interface und Implementation erreichen nur eben mit den Funktionen, die von ausserhalb der Unit nicht sichtbar sind?
Du kannst die Forwards ganz oben im Implementationsteil setzen und die eigendliche Funktions-Implementierung an belibiger Stelle im Implementationsteil (aber irgendwann nach den Forward, sonst macht es keinen Sin)

Auslagern der Funktionen geht natürlich auch. Mann sollte sich jedoch überlegen, ob es auch logisch passt. Eine Unit sollte schon logisch zusammengehören. Zum Beispiel alles, was zur Textverarbeitung gehört, alles was zur Graphik gehört, etc. Wenn die Units zu groß werden kann mann sich noch feinere Unterteilungen überlegen.

marcov
Beiträge: 1100
Registriert: Di 5. Aug 2008, 09:37
OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
CPU-Target: 32/64,PPC(+64), ARM
Wohnort: Eindhoven (Niederlande)

Re: Deklaration von Variablen

Beitrag von marcov »

MVC ist meistens ein Web Muster (also stateless GUI), und IMHO modelliert es stateful GUI apps schlecht.

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

@Thandor
Thandor hat geschrieben:Du kannst die Forwards ganz oben im Implementationsteil setzen und die eigendliche Funktions-Implementierung an belibiger Stelle im Implementationsteil (aber irgendwann nach den Forward, sonst macht es keinen Sinn).

Ok, dann würde das ganz bei mir ungefähr so strukturiert werden:

Code: Alles auswählen

 
unit Timer_GUImainForm
{hier steht das ganze Vorgplänkel der Unit bis zum Interfaceteil}
 
interface
Uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, DateUtils, Clipbrd, Crt;
 
Type
    //Deklaration der FormKlasse
    TForm1 = class(TForm)
      {hier deklariere ich die GUI-Elemente und deren Events, als Teil des "View-Modul"(MVC-Model)}
    Private
      {hier deklariere ich Prozeduren und Globale Variablen der Klasse, als Teil des "Controler-Moduls"(MVC-Model)}
    Public
       {hier deklariere ich Prozeduren und Globale Variablen, als Teil des "Controler-Modul"(MVC-Model)}
 
    //Deklaration von weiteren Klassen
       {hier deklariere ich weitere Klassen in dieser UNIT}
 
Var
Form1: TForm1;
 
implementation
//Vorabgeplänker
    uses unit_A, Unit_B;
    {$R *.lfm}
 
// Dekleration von
    {Hier deklarier ich mir noch ein paar private Klassen}
 
//(Forward)-Deklaration von allgemeinen "privaten Unit-Prozeduren", die nicht im Interface-Teil der Unit deklariert wurden
//Auf diese Prozeduren möchte ich zukünftig aus allen Klassen dieser Unit zugreifen können
    procedure Prozedur1;
    procedure Prozedur2;
 
//Implementierung der FormKlasse-Methoden
    {procedure TForm1.ControllerProzeduren - alle Prozeduren die zum Control-Modul(MVC) gehören: z.B. TimerStart}
    {procedure TForm1.GUI-Event - alle Prozeduren die durch die GUI-Elemente aufgerufen werden, als Teil des View-Moduls(MVC): z.B. TimerStart}
 
//Implementierung der weiteren öffentlichen Klassen
    {hier implementiere ich die weiteren Klassen der UNIT, welche auf Prozedure 1 und Prozedur 2 zugreifen}
 
//Implementierung der weiteren privaten Klassen
    {hier implementiere ich die weiteren Klassen der UNIT, welche auf Prozedure 1 und Prozedur 2 zugreifen}
 
//Implementierung von allgemeinen "privaten Unit-Prozeduren"
    procedure Prozedur1;
       {deklarationteil für prozedur1}
    begin
       {Implementierung allg. Prozedur 1}
    end;
 
    procedure Prozedur2;
       {deklarationteil für prozedur2}
    Begin
        {Implementierung allg. Prozedur 2}
    end;
 
 


Wird das so funktionieren bzw. meinst Du das so? Dabei geht es mir insbesondere um die Implementierung der weiteren Klassen und allg. privaten Unit-Prozeduren (der Rest hab ich bereits ausprobiert und das funktioniert bei mir). Hier würde sich die Frage anschliessen: Darf Prozedur 1 auch die Prozedur 2 verwenden, oder spiel hier die Reihenfolge eine Rolle?

@marcov
marcov hat geschrieben:MVC ist meistens ein Web Muster (also stateless GUI), und IMHO modelliert es stateful GUI apps schlecht.

MVC ist kein dediziertes Web-Muster (ich nehme mal an du meinst "Muster für Web-Applikationen"), mir ist auch nicht ganz klar, wie Du darauf kommst, dass das GUI meiner Application unbedingt "stateful" sein muss?! Und warum es "stateless" GUIs schelcht "modelliert" ist mir auch nicht ganz klar (davon abgesehen "modelliert" es gar keine GUIs sondern, wenn überhaupt ganze Applicationen, oder was meinst Du genau?).

Thandor
Beiträge: 153
Registriert: Sa 30. Jan 2010, 18:17
OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 3.0 mit FPC 3.2.2 (32Bit + 64bit)
CPU-Target: 64Bit
Wohnort: Berlin

Re: Deklaration von Variablen

Beitrag von Thandor »

Ja das sollte so funktionieren, probiere es am besten einfach mal aus.

Albin
Beiträge: 20
Registriert: Fr 15. Jul 2016, 13:24

Re: Deklaration von Variablen

Beitrag von Albin »

Thandor hat geschrieben:Ja das sollte so funktionieren, probiere es am besten einfach mal aus.


So bin endlich dazu gekommen, es zu testen, hat zunächst nicht geklappt, da in meinem voherigen Beispiel das entscheidene Keyword "forward;" nach der Deklaration gefehlt hat, hier das korrekte CodeSnippet:

Code: Alles auswählen

 
implementation
    uses unit1;
    {$R *.lfm}
 
    //Forwarddeklaration General Procedures
    procedure testprocedure1; forward; {=> das keyword "forward;" muss verwendet werden}
 
    { TForm2 }
 
    //Implementation GUI-Events
    procedure TForm2.Button1Click(Sender: TObject);
    begin
        testprocedure1;
    end;
 
    //Implementation General Procedures
    procedure testprocedure1;
    begin
    end;
 

Antworten