Singleton in der Applikation verwenden.

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Singleton in der Applikation verwenden.

Beitragvon charlytango » 27. Jan 2019, 13:27 Singleton in der Applikation verwenden.

Hi,

in http://www.lazarusforum.de/viewtopic.php?f=18&t=11936 bekam ich den Rat für Programmeinstellungen oder Datenbankanbindungen das Singleton-Konzept zu verwenden. Das klappt mittlerweile ganz gut mit der Erkenntnis, dass es DEN code für ein Singleton-Pattern nicht gibt. Der scheint je nach Programmierer und Verwendungszweck/Anforderungen sehr variabel zu sein.

Nachdem die Programmaufgaben die ich in Singletons packe für das gesamte Programm zur Verfügung stehen müssen und auch beim Start im wesentlichen auch vorhanden sein sollten erzeuge ich die Objekte im initialization Abschnitt der Unit.

Klappt alles soweit gut.

Nur der Zugriff zu den Objekten direkt im restlichen Code ist in einigen Singleton-Varianten recht aufwendig.

Code: Alles auswählen
 
procedure xy
var
  s: TMySettings; // class
begin
  s := GetMySettings; // GetMySettings nehme ich jetzt mal als als Funktion die den Singleton zurückgibt
  s.Irgendwas := Wert;
end;


das von braunbär vorgeschlagene Konstrukt scheint mir etwas zu aufwendig, um nur eine Einstellung auszulesen.
Daher habe ich die Variable des Singleton im gesamten Programm sichtbar gemacht.

Code: Alles auswählen
interface
....
var
 MySettings: TMySettings = nil;
 
implementation
....


was es im Code erlaubt einfach
Code: Alles auswählen
MySettings.Irgendwas := Wert;

zu schreiben

Gibt es dazu Einwände ?

Dann ist auch noch der zeitliche Ablauf der Erstellung der verschiedenen Singleton-Objekte und die Rückmeldungen an den Benutzer ein Thema.
Wie schafft man es z.B. das Objekt mit den Einstellungen vor dem Objekt mit den Datenbankzugriffen zu erstellen ? Nur die Reihenfolge in der uses-Klausel? Oder das Objekt so zu strukturieren dass erst nur das Objekt ohne Funktion erzeugt wird (wobei dann die Reihenfolge egal wäre) und mit einer init-Prozedur an einer bestimmten Stelle das Objekt erst mit Leben füllt.

Und wie bekomme ich eine Rückmeldung z.B. in einer Splash Screen hin? z.B. irgend ein Logo auf einer Form und z.B. in einem Memo was gerade passiert um das Programm zu starten. Mir geht es nicht darum wie man eine Splash-Screen erstellt und einbindet sondern wie die diversen Singleton-Objekte damit kommunizieren können?

THX
charlytango
 
Beiträge: 164
Registriert: 12. Sep 2015, 11:10
Wohnort: Wien
OS, Lazarus, FPC: Laz 2.0.3 FPC 3.2 | 
CPU-Target: Win 32Bit, 64bit
Nach oben

Beitragvon Michl » 27. Jan 2019, 14:06 Re: Singleton in der Applikation verwenden.

Nur so am Rande. Ich finde es nicht so günstig, großartig irgendwelche Operationen vor Programmstart zu machen (im Initialization-Block, wegen Logging, Exceptionbehandlung etc.). Wollte ich auch schon in dem anderen Thread schreiben, da aber jeder einen anderen Geschmack hat, und letztlich jeder machen kann, was er will, hatte ich es gelassen.

Eine Möglichkeit, die ich oft nutze, ist On-Demand, also die Erstellung einer Unique-Instanz auf Aufforderung. Der Vorteil ist, daß sie erst erstellt wird, wenn tatsächlich auf sie zugegriffen wird. Ein Nachteil ist, daß diese sich nicht so gut debuggen lässt (Debugger springt als erstes in die Getter-Funktion).

Ansonsten ist das Vorgehen gleich, wie du es bisher hast und auch gut so.

Würde dann in etwa so ausehen:
Code: Alles auswählen
unit Unit1;
 
{$mode objfpc}{$H+}
 
interface
 
type
 
  { TFoo }
 
  TFoo = class
  public
    procedure WriteTest;
  end;
 
function Foo: TFoo;
 
implementation
 
var
  FFoo: TFoo;
 
function Foo: TFoo;
begin
  if not Assigned(FFoo) then
    FFoo := TFoo.Create;
  Result := FFoo;
end;
 
{ TFoo }
 
procedure TFoo.WriteTest;
begin
  writeln('TFoo.WriteTest');
end;
 
initialization
  FFoo := nil;
 
finalization
  if Assigned(FFoo) then
    FFoo.Free;
 
end.


Code: Alles auswählen
program project1;
 
uses Unit1;
 
begin
  Foo.WriteTest;
end.
Code: Alles auswählen
type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 
Michl
 
Beiträge: 2320
Registriert: 19. Jun 2012, 11:54
OS, Lazarus, FPC: Win7 Laz 1.7 Trunk FPC 3.1.1 Trunk | 
CPU-Target: 32Bit/64bit
Nach oben

Beitragvon kupferstecher » 27. Jan 2019, 23:03 Re: Singleton in der Applikation verwenden.

Das Problem an Initialization ist, dass es vor der LCL-Initialisierung stattfindet, also bevor auch nur eine GUI-Komponente initialisiert wurde. Dadurch ist es oft nicht nutzbar. Ich mach immer eine Unit mit allen Initialisierungen in einer Procedur GlobalInit. Diese ruf ich in der LPR-Datei vor Application.Run auf.
kupferstecher
 
Beiträge: 217
Registriert: 17. Nov 2016, 11:52

Beitragvon m.fuchs » 28. Jan 2019, 00:39 Re: Singleton in der Applikation verwenden.

charlytango hat geschrieben:
Code: Alles auswählen
 
procedure xy
var
  s: TMySettings; // class
begin
  s := GetMySettings; // GetMySettings nehme ich jetzt mal als als Funktion die den Singleton zurückgibt
  s.Irgendwas := Wert;
end;


das von braunbär vorgeschlagene Konstrukt scheint mir etwas zu aufwendig, um nur eine Einstellung auszulesen.


Code: Alles auswählen
 
procedure xy
begin
  GetMySettings.Irgendwas := Wert;
end;

Wie wäre es so? Ist dann nur noch eine Zeile und keine gesonderte Deklaration mehr.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
m.fuchs
Lazarusforum e. V.
 
Beiträge: 2067
Registriert: 22. Sep 2006, 18:32
Wohnort: Berlin
OS, Lazarus, FPC: Winux (Lazarus 2.0, FPC 3.0.4) | 
CPU-Target: x86, x64, arm
Nach oben

Beitragvon fliegermichl » 28. Jan 2019, 09:48 Re: Singleton in der Applikation verwenden.

Man kann ja mittlerweile auch Properties ausserhalb von Klassen definieren.
Code: Alles auswählen
 
interface
 function GetMySettings : TMySettings;
 property MySettings : TMySettings read GetMySettings;
implementation
var fMySettings : TMySettings;
 
function GetMySettings : TMySettings;
begin
 if not Assigned(fMySettings) then fMySettings := TMySettings.Create;
 Result := fMySettings;
end;
 


Dann kann man einfach MySettings.Irgendwas := Irgendwer verwenden.
fliegermichl
 
Beiträge: 335
Registriert: 9. Jun 2011, 08:42

Beitragvon charlytango » 30. Jan 2019, 11:10 Re: Singleton in der Applikation verwenden.

kupferstecher hat geschrieben:Das Problem an Initialization ist, dass es vor der LCL-Initialisierung stattfindet, also bevor auch nur eine GUI-Komponente initialisiert wurde. Dadurch ist es oft nicht nutzbar. Ich mach immer eine Unit mit allen Initialisierungen in einer Procedur GlobalInit. Diese ruf ich in der LPR-Datei vor Application.Run auf.


Also gibt es wohl wie immer keinen Königsweg :(
Daher wird es eine Kombination aus den Strategien aller beteiligten Poster -- Danke für eure Mühe!

@Kupferstecher:
Rufst du in der .LPR Datei deine Init-Prozedur folgendermaßen auf ?

Code: Alles auswählen
Unit4711.GlobalInit;


oder gibt es da andere Vorschriften in der .LPR ?

Eine Frage wurde noch nicht beantwortet:
Wie können die Singleton-Objekte (nehmen wir mal an es handelt sich um ein Objekt zur Datenbankverbindung) mit der Splashscreen kommunizieren?

Auszug aus möglichen Meldungen f die Splashscreen:
    Initialisierungsdaten f DB laden
    DB Verbindung aufbauen
    Programmeinstellungen aus der DB laden
    DLL xyz laden
    Rechtesystem erzeugen
    Logging vorbereiten
    Menüs erzeugen
und andere mehr. Für mittlere und größere Projekte ist einiges zu tun bevor die Applikation einsatzbereit ist. Den User da ohne Info warten zu lassen wäre schlechter Stil.

Wie löst ihr so eine Aufgabe? (An Forumsadmin -- gern auch in einen eigenen Thread verschieben)
charlytango
 
Beiträge: 164
Registriert: 12. Sep 2015, 11:10
Wohnort: Wien
OS, Lazarus, FPC: Laz 2.0.3 FPC 3.2 | 
CPU-Target: Win 32Bit, 64bit
Nach oben

Beitragvon kupferstecher » 30. Jan 2019, 11:28 Re: Singleton in der Applikation verwenden.

charlytango hat geschrieben:Rufst du in der .LPR Datei deine Init-Prozedur folgendermaßen auf ?

Ja, genau. So sieht das dann bei mir aus, händisch habe ich nur "GlobalInit" und "GlobalDeinit" eingetragen:
Code: Alles auswählen
begin
  RequireDerivedFormResource := True;
  Application.Initialize;
  Application.CreateForm(TMainForm, MainForm);
  GlobalInit;    // <-- Initialisierung
  Application.Run;
  GlobalDeinit;  // <-- Aufräumen
end.
kupferstecher
 
Beiträge: 217
Registriert: 17. Nov 2016, 11:52

• Themenende •

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste

porpoises-institution
accuracy-worried