Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Ausgliedern von Functionen in externe Unit (https://www.delphipraxis.net/147928-ausgliedern-von-functionen-externe-unit.html)

Jens Hartmann 19. Feb 2010 06:05


Ausgliedern von Functionen in externe Unit
 
Guten Morgen zusammen,

ich hab mal ne Frage zum ausgliedern von Funktionen in eigene Units. Ich habe einige Funktionen (ca. 20 Stck) die für das versenden von E-Mails zuständig sind. Diese Funktionen greifen allerdings auch auf Komponenten meiner Hauptform zu.

Mach es Sinn, oder besser gesagt wie gehe ich das an, diese Funktionen in einen eigene Unit zu packen, um in meinem Hauptformular mal wieder etwas mehr Ordnung zu bekommen.

Ist es OK, wenn ich in dieser Unit dann z.B. schreiben würde...

Delphi-Quellcode:
TForm1.Caption
Oder ist es dann besser den Wert z.B. als Var. der Funktion oder als proberty zu übergeben.
Delphi-Quellcode:
function(var Caption : String) : Boolean
oder so ähnlich.

Danke schon mal für Eure antworten

Gruß Jens

angos 19. Feb 2010 06:24

Re: Ausgliedern von Functionen in externe Unit
 
Hi,

da kommt es meines Erachtens immer auf die genaue Funktion an.

Dein Beispiel wirkt ein bisschen konstruiert. Eine Funktion zur Änderung der Caption würde ich jetzt nicht unbedingt auslagern. Gerade diese Funktionalität gehört doch zum Formular und sollte durch eine Funktion des Formulars bereitgestellt werden

Gruß
angos

Tyrael Y. 19. Feb 2010 07:24

Re: Ausgliedern von Functionen in externe Unit
 
Ich würde so etwas in drei Teile gliedern, wenn es konsequent sein soll.

1. Das Formular:
...enthält keinen "echten" SourceCode
...nur das Formular, also Aussehen und Anordnung betreffender Code steht hier

2. Funktion/Klassen
...in diesen Dateien sind Funktionen/Klassen, die allgemein ein Aufgabe verrichten
...diese Funktionen/Klassen kennen denjenigen, von dem sie genutzt werden gar nicht

3. Verbindung
...hier werden das Formular und die Funktionen/Klassen benutzt
...diese Klasse verbindet die Funktionalität mit dem Formular

Jens Hartmann 19. Feb 2010 08:11

Re: Ausgliedern von Functionen in externe Unit
 
Zitat:

Zitat von Tyrael Y.
3. Verbindung
...hier werden das Formular und die Funktionen/Klassen benutzt
...diese Klasse verbindet die Funktionalität mit dem Formular

Das ist zur Zeit mein Verständnisproblem. Wie mach ich sowas?

Gruß Jens

Tyrael Y. 19. Feb 2010 08:18

Re: Ausgliedern von Functionen in externe Unit
 
Delphi-Quellcode:

unit SuperFunktionen...

  function HoleBetreffzeileVonEMail(): string;

end.


unit VerbinderKlasse
uses
 ...meinTollesFormularUnit, SuperFunktionen...
...
type
  TVerbinderKlasse = class
  ...
   meinFormular: TMeinFormular;
  ...
    procedure SetzeEMailBetreffZeile();

implementation

procedure TVerbinderKlasse.Create()
begin
..
  meinFormular = TMeinFormular.Craete(..
..
end;


procedure SetzeEMailBetreffZeile();
begin
  meinFormular.Betreffzeile := HoleBetreffzeileVonEMail();
end;
...
ein Beispiel...hoffe es ist verständlich

Jens Hartmann 19. Feb 2010 08:20

Re: Ausgliedern von Functionen in externe Unit
 
Ahhhh,

danke. Das werde ich mal durcharbeiten. Kennst Du eventuell ein Tutorial, wo sowas beschrieben ist.

Danke schon mal und

Gruß Jens

Tyrael Y. 19. Feb 2010 08:41

Re: Ausgliedern von Functionen in externe Unit
 
Ne sorry, leider kenn ich kein Tutorial zu diesem Thema.

himitsu 19. Feb 2010 08:55

Re: Ausgliedern von Functionen in externe Unit
 
Zitat:

Zitat von Jens Hartmann
Diese Funktionen greifen allerdings auch auf Komponenten meiner Hauptform zu.

Welche Komponenten sind das denn so alles?

z.B. die Indy zur Komunikation:
Diese würde ich dann lokal/manuell in der Unit erzeugen
und nicht die nehmen, welche auf einer Form liegen.

Bei TLabel, gäbe es 2-3 grundsätzliche Möglichkeiten

1) der Text wird in der Unit gespeichert und die Form fragt von sich aus abundzu diesen Text ab und zeigt ihn dann an.
z.B. über eine Funktion ala "GibMirDenStatusText"

2) man übergibt die Insanz zu dem Label an die Unit
z.B. bei Start des Verarbeitung
Delphi-Quellcode:
funktion LadeEMails(status: TLabel): Boolean;
3) oder man übergibt (was ich für besser halte) eine Callback-Prozedur
Delphi-Quellcode:
type TCallback = procedure(text: String) of object;
funktion LadeEMails(status: TCallback ): Boolean;
so wären die Funktionen in der externen Unit komplett von der GUI getrennt und es hängt jetzt von der GUI ab, was sie im Callback mit diesem Text macht.
Sowas kennst du vorallem von den vielen OnIrgendwas-Ereignissen der VCL.
Die Funktion/Komponente brauch nicht zu wissen, wie der Rückgabewert angezeigt/verarbeitet wird und der Programmierer hat dann alle Möglichkeiten offen


Eventuell macht es sich auch nicht schlecht, wenn du deine Prozeduren in einer Klasse kapselst.

xZise 19. Feb 2010 10:15

Re: Ausgliedern von Functionen in externe Unit
 
Vielleicht sollte man dann aber auch zu einer Klasse greifen oder nicht?

Also sowas wie:
Delphi-Quellcode:
type
  TEMailHandler = class
  private
    FOnLEM : TLoadEmailNotify;
  public
    property OnLoadEmail : TLoadEmailNotify read FOnLEM write FOnLEM;

    procedure LoadEmails;
  end;
Natürlich nicht nur mit den Bruchstücken, sondern mit mehr Content. Ich selber kenne ja kaum die Struktur deiner Klasse/Unit die du auslagern willst. Ansonsten mache ich das auch einfach so, dass ein paar Sachen (um auf die Form zuzugreifen) halt übergeben werden.

MfG
Fabian

Jens Hartmann 20. Feb 2010 08:55

Re: Ausgliedern von Functionen in externe Unit
 
Hallo zusammen,

also erstmal besten Dank für die vielen antworten. Ich denke den Sinn habe ich verstanden, allerdings die Ausführung noch nicht so ganz. Ich nehme jetzt mal ein für mich aktuelles Beispiel. Ich möchte verschiedene Werte aus einer Datenbank habe. Hier z.B. jetzt die Uhzeit wann das nächste Mal eine E-Mail automatisch versendet wird. Diese Funktion brauche ich mehrmals, da ich mehrer Timer habe, die dieses machen sollen.

Code:
Timer 1 - E-Mail senden an Gruppe 1
Timer 2 - E-Mail senden an Gruppe 2
...
Timer n - E-Mail....
usw.
das heißt...
Delphi-Quellcode:
function SetTimer1IntervalEMailStart : Boolean;
var
  TimeNow : String;
  TimeSend : String;
const
  HalfDay = 43200000;
begin
  TimeNow := TimeToStr(Now);//Aktuelle Zeit ist ja soweit kein Problem
  TimeSend := '22:57:00';//Nächste Startzeit soll jetzt je nach Timer aus DB gelesen werden
Da ich ja jetzt je nach Timer eine andere Startzeit aus der DB brauch, denke ich müsste die function noch einen Übergabeparameter besitzen welcher Timer, also evtl. so..

Delphi-Quellcode:
function SetTimer1IntervalEMailStart(var Timer : integer) : Boolean;
Um dann jetzt den Wert lesen zu können, müsste ich momentan sowas machen..

Delphi-Quellcode:
  TForm1.Qry_TimerRead.SQL.Text := 'SELECT * FROM EMAIL
        ' WHERE ID = :Id';
  TForm1.Qry_TimerRead.ParamByName('Id').Value := Timer;
  TForm1.Qry_TimerRead.Open;
  TimeSend := TimeToStr(TForm1.Qry_TimerRead.FieldbyName('TIME').AsTime);
Jetzt wäre halt die Frage, wie ich sowas auslagern würde ohne immer noch das Form1 etc. zu nutzen.

Ich hoffe ich konnte so ungefähr beschreiben was ich meine

Gruß Jens

xZise 20. Feb 2010 09:03

Re: Ausgliedern von Functionen in externe Unit
 
Moin,
ich hätte eine Funktion für die Klasse TForm1 geschrieben, die dir den Wert für den Timer holt. Und dann eine Funktion die den Unterschied misst (SetTimer1IntervalEMailStart).
Ich weiß leider nicht wie die anderen SQL-Requests aussehen. Aber wenn sie ähnlich sind (z.B. nur die ID anders), dann geht das ganz gut.

Alternativ machst du noch ein Klasse die selber die Datenbank ist, und ein paar Informationen „wrappt“.

MfG
Fabian

Jens Hartmann 20. Feb 2010 09:20

Re: Ausgliedern von Functionen in externe Unit
 
Ich weiß allerdings nicht wie ich das mache. Deswegen fragte ich oben schon mal nach einem Tutorial

Ich will mal so sagen, wenn ich folgende function mit den entsprechenden Übergabe Werten in eine externe Unit/Klasse packen will, wo muss ic dann was, und vorallem damit ich es auch versteh wie und warum machen.
Delphi-Quellcode:
function TForm1.SetTimer1IntervalEMailStart : Boolean;
var
  TimeNow : String;
  TimeSend : String;
const
  HalfDay = 43200000;
begin
  SendEMailTimer1.Enabled := false;
  TimeNow := TimeToStr(Now);//Aktuelle Zeit
  TimeSend := '22:57:00';//Nächste Startzeit
  if TimeSend > TimeNow then //Prüfung ob Sendezeit für aktuellen Tag schon vorbei
    begin
      //Zeitpunkt für nächsten Step festlegen
      SendEMailTimer1.Interval := MilliSecondsBetween(frac(StrToTime(TimeNow)),
        frac(StrToTime(TimeSend)));
    end
  else
    begin
      //Zeitpunkt festlegen wenn Step für aktuellen Tag vorbei
      SendEMailTimer1.Interval := HalfDay - MilliSecondsBetween(frac(StrToTime(TimeNow)),
        frac(StrToTime(TimeSend)))+ HalfDay;
    end;
  SendEMailTimer1.Enabled := true;
end;
Gruß Jens

xZise 20. Feb 2010 09:25

Re: Ausgliedern von Functionen in externe Unit
 
Wie du was machst?

MfG
Fabian

Jens Hartmann 20. Feb 2010 09:26

Re: Ausgliedern von Functionen in externe Unit
 
siehe oben, ich habe meinen letzten Beitrag geändert...

DeddyH 20. Feb 2010 09:28

Re: Ausgliedern von Functionen in externe Unit
 
Wenn Du die gesamte DB-Funktionalität in eine oder mehrere Klassen packst, kannst Du die Oberfläche sauber von dieser Funktionalität trennen. Dazu müssten dann alle DB-Kompos wie die Query runter vom Formular und von der Klasse erzeugt und verwaltet werden. Das Formular ruft dann nur noch eine Methode der Klasse auf, welche sich um den Rest kümmert und die ermittelten Daten zurückgibt. Das ist zwar am Anfang eine Menge Arbeit, aber wenn man das gut durchdenkt hat man ein sauberes Design.

xZise 20. Feb 2010 09:34

Re: Ausgliedern von Functionen in externe Unit
 
Moin,
wo ist da jetzt die DB Funktionalität? Trotzdem hätte ich ein paar Verbesserungsvorschläge:
  1. Wandle die Zeiten nicht in einen String um (wozu, wenn du sie nachher eh wieder zurückumwandelst)
  2. Damit hängt zusammen: Teste nicht String > String ;) Sondern eher Time > Time, das funktioniert eher
  3. Deine zwei Pfade sind sogut wie ähnlich. Der einzige Unterschied ist, dass du im else-Zweig einen ganzen Tag hinzufügst (a - b + a = 2a - b mit a := halber Tag und b := Zeitunterschied). Das heißt zuerst setzt du immer Intervall auf b und guckst dann, ob du dieses Intervall aber erstmal von einem Tag abziehen musst.

Und ansonsten mach es so wie Detlef es vorschlägt:
Du schreibst dir eine Klasse die alle Zugriffe kapselt und dann rufst du nur noch .GetTimer(....) oder so auf.

MfG
Fabian

DeddyH 20. Feb 2010 09:47

Re: Ausgliedern von Functionen in externe Unit
 
Zitat:

Zitat von Jens Hartmann
Delphi-Quellcode:
  TForm1.Qry_TimerRead.SQL.Text := 'SELECT * FROM EMAIL
        ' WHERE ID = :Id';
  TForm1.Qry_TimerRead.ParamByName('Id').Value := Timer;
  TForm1.Qry_TimerRead.Open;
  TimeSend := TimeToStr(TForm1.Qry_TimerRead.FieldbyName('TIME').AsTime);
Jetzt wäre halt die Frage, wie ich sowas auslagern würde ohne immer noch das Form1 etc. zu nutzen.

Ich hoffe ich konnte so ungefähr beschreiben was ich meine

Gruß Jens

Das sieht mir sehr nach DB aus, oder?

Jens Hartmann 20. Feb 2010 09:54

Re: Ausgliedern von Functionen in externe Unit
 
Ich habe jetzt mal die Datenbankabfrage in eine andere Funktion gelegt. Da ich noch am Anfang dieser Verarbeitung bin und genau aus diesem Grund auch jetzt schon frage, ist das mit der vielen arbeit nicht so das Problem. Ich habe zum jetzigen Zeitpunkt lediglich die Funktion geprüft und dessen Inhalt getestet. Das was ich vorhabe, funktioniert und muss halt jetzt umgesetzt werden.

Ich habe zur Zeit nur eine Testprogramm geschrieben um die Timer Komponenten und die E-Mail funktion zu Simulieren und das mit Erfolg. Ich will nur der Übersichthalber nicht den Gesamten Code hier einstellen, weil sonst eh keiner mehr weiß was ich will.

Ich habe jetzt z.B. mal die Datenbankabfrage der Uhrzeit ausgegliedert und als Funkton ausgelagert. Damit sieht man vieleicht was ich vorhabe.

Zu der Umwandlung von Time nach String etc. das kommt nur weil ich noch in einem Testprogramm probiere und auch die gesamte Exception Behandlung und auch denn Rest des Programmteils noch gar nicht angepasst habe. Ich habe das ganze einfach mal schnell zusammen getippt, um überhaupt mal meinen Gedankengang zu prüfen.

Hier mal den Schritt den gerade veändert habe um die DB Abfrage Uhrzeit zu realisieren..

Delphi-Quellcode:
//die function SetTimerInterbalEMailStart wird durch das FormCreate ausgelößt
function TForm1.SetTimer1IntervalEMailStart : Boolean;
var
  TimeSend : TTime;
const
  HalfDay = 43200000;
begin
  SendEMailTimer1.Enabled := false;
  TimeSend := ReadTimerTime(1); //'22:57:00';//Nächste Startzeit
  if TimeSend > Time then //Prüfung ob Sendezeit für aktuellen Tag schon vorbei
    begin
      //Zeitpunkt für nächsten Step festlegen
      SendEMailTimer1.Interval := MilliSecondsBetween(frac(Time),
        frac(TimeSend));
...

function TForm1.ReadTimerTime(Timer : integer) : TTime;
begin
  Qry_TimerTime.SQL.Text := 'SELECT ZEIT FROM EMAILGRUPPEN WHERE ID = :Id';
  Qry_TimerTime.ParamByName('Id').AsInteger := Timer;
  Qry_TimerTime.Open;
  Result := Qry_TimerTime.FieldByName('ZEIT').Value;
end;
Gruß Jens

xZise 20. Feb 2010 10:19

Re: Ausgliedern von Functionen in externe Unit
 
Zitat:

Zitat von DeddyH
[...]Das sieht mir sehr nach DB aus, oder?

Aber nicht den den Code was er nachher genannte hatte. Und auch da kannst du schlecht sagen, was er da einfach in eine Funktion schreiben kann.

MfG
Fabian

DeddyH 20. Feb 2010 10:53

Re: Ausgliedern von Functionen in externe Unit
 
Ich musste ein bisschen suchen, aber worauf ich eigentlich hinauswollte: http://www.delphipraxis.net/internal...t.php?t=150471

Jens Hartmann 20. Feb 2010 11:12

Re: Ausgliedern von Functionen in externe Unit
 
Zitat:

Zitat von DeddyH
Ich musste ein bisschen suchen, aber worauf ich eigentlich hinauswollte: http://www.delphipraxis.net/topic150...tion+mehrschic ... ungen.html

Ich glaube das bringt mich weiter. Ich werde das mal genauer ansehen und dann bei Gelegenheit auch Euch zu kommen.

Danke und Gruß Jens :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:19 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz