![]() |
Designfrage zu Klassen- und Instanzproperties
Ich hätte für eine Konfigurationsklasse gern die Möglichkeit, eine sagen wir mal initiale global verfügbare Instanz anzulegen als auch eine (temporäre) lokale. Meine bisherige Umsetzung:
Delphi-Quellcode:
Meine Frage: ist das ein gangbarer Weg, oder baue ich mir hier ein Anti-Pattern, das mir früher oder später um die Ohren fliegt?
type
TMyConfig = class strict private class var FInstance: TMyConfig; class function GetInstance: TMyConfig; static; class destructor ClassDestroy; private FFeld: integer; public property Feld: integer read FFeld write FFeld; class property Instance: TMyConfig read GetInstance; end; ... class function TMyConfig.GetInstance: TMyConfig; begin if not Assigned(FInstance) then FInstance := TMyConfig.Create; Result := FInstance; end; class destructor TMyConfig.ClassDestroy; begin FInstance.Free; end; Danke fürs Lesen |
AW: Designfrage zu Klassen- und Instanzproperties
Das nennt sich „Singleton“. Such mal danach, einmal tief Luft holen und dann lesen.
|
AW: Designfrage zu Klassen- und Instanzproperties
Danke, das ist mir bekannt, auch, dass das oft als verpönt angesehen wird. Ich nutze es aber gern als Alternative zu globalen Variablen.
|
AW: Designfrage zu Klassen- und Instanzproperties
Wenn es wirklich nur eine Instanz für diese Klasse in deinem Programm geben soll, dann spricht m.M. nichts gegen deinen Ansatz. Die Alternative wäre, diese eine Instanz jeweils als Parameter oder anderweitig mitzugeben wo sie gebraucht wird. Das halte ich aber für völlig unpragmatisch und in vielen Fällen für kontraproduktiv.
Natürlich gibt es andere Ansätze, mit denen diese Singleton-Instanz vermieden werden kann, wobei in den meisten Fällen dann doch intern wieder nur eine Instanz vorgehalten wird, was ja auch eigentlich die Vorgabe in diesem Anwendungsfall ist. Jetzt irgendwelche Klimmzüge zu machen, um formal dem Singleton-Shaming zu entgehen, erscheint mir nicht wirklich sinnvoll. Wenn du es etwas flexibler haben möchtest, dann implementiere eine Factory-Funktionalität, die du bei Bedarf anpassen kannst um ein anderes Verhalten für Tests oder als Mock zu ermöglichen.
Delphi-Quellcode:
type
TMyConfigClass = class of TMyConfig; TMyConfig = class strict private class var FMyConfigClass: TMyConfigClass; class var FInstance: TMyConfig; class function GetInstance: TMyConfig; static; class destructor ClassDestroy; private FFeld: integer; public property Feld: integer read FFeld write FFeld; class property Instance: TMyConfig read GetInstance; class property MyConfigClass: TMyConfigClass read FMyConfigClass write FMyConfigClass; end; class function TMyConfig.GetInstance: TMyConfig; begin if not Assigned(FInstance) then begin if Assigned(FMyConfigClass) then FInstance := FMyConfigClass.Create else FInstance := TMyConfig.Create; end; Result := FInstance; end; class destructor TMyConfig.ClassDestroy; begin FInstance.Free; end; |
AW: Designfrage zu Klassen- und Instanzproperties
Danke, Uwe, so flexibel benötige ich das gar nicht. Mir geht es darum, dass es eine "Hauptinstanz" geben soll, auf die ich überall, wo sie benötigt wird, zugreifen kann. Will ich aber eine andere Konfiguration testen, ohne mir die Hauptinstanz zu zerstören, erzeuge ich einfach eine weitere, stelle sie entsprechend ein, schaue, ob sie so funktioniert und kann im Erfolgsfall dann in der Hauptinstanz die neuen Werte zuweisen. So war mein Denkansatz.
|
AW: Designfrage zu Klassen- und Instanzproperties
Ich habe so etwas mal mit 2 globalen Variablen und einer Funktion realisiert:
Delphi-Quellcode:
Wenn globVarTmp etwas zugewiesen wird, wird die Instanz verwendet, sonst die Main-Variable.
globVarMain: TObject = nil;
globVarTmp: TObject = nil; function MyVar: TObject; begin if Assigned(globVarTmp) then Exit(globVarTmp); if not Assigned(globVarMain) then globVarMain := TObject.Create; Exit(globVarMain); end; |
AW: Designfrage zu Klassen- und Instanzproperties
Dann nimm doch einen Record
Delphi-Quellcode:
var
MyConfig = record Feld: integer; end;
Delphi-Quellcode:
Kannst den Typen auch einzeln deklarieren
var
MyConfig = record private FFeld: integer; public property Feld: integer read FFeld write FFeld; end; und seit Delphi 10.4.2 gibt es aus für Records sowas Constructor/Destructor, bzw. Class Constructor/Class Destructor, also Initialize/Finalize ( ![]() oder direkt ALLES als Class
Delphi-Quellcode:
type
MyConfig = class abstract strict private class var FFeld: integer; public class property Feld: integer read FFeld write FFeld; end; |
AW: Designfrage zu Klassen- und Instanzproperties
Abgesehen davon, dass dein GetInstance nicht thread-safe ist, sieht das in Ordnung aus.
Wie bei so vielen Prinzipien, (Anti-)Patterns etc ist es wichtig zu verstehen, warum sie generell als gut/schlecht angesehen werden. Dir muss halt klar sein, dass du durch ein TMyConfig.Instance in deinem konsumierenden Code dir sowieso eine hartcodierte Abhängigkeit einhandelst - wie "schlimm" das ist, kommt darauf an, was alles in TMyConfig steckt oder auch nicht. Da du aber mit dem class function Instance Ansatz daran gehst und nicht wie oft anders implementiert NewInstance etc überschreibst um auf Biegen und Brechen zu verhindern, dass irgendjemand jemals eine 2. Instanz davon erzeugt ist das imho weniger problematisch. |
AW: Designfrage zu Klassen- und Instanzproperties
Danke, dann lasse ich das jetzt so.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:25 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