Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Programmeinstellungen organisieren (https://www.delphipraxis.net/182474-programmeinstellungen-organisieren.html)

Blamaster 27. Okt 2014 20:37

Delphi-Version: 7

Programmeinstellungen organisieren
 
Hi,

ich versuche gerade den Code eines älteren Projekt ein wenig neu zu organisieren. Konkretes Ziel ist eine striktere Trennung von Gui <-> Logik.
Soweit klappt das auch alles schon so wie es soll.

Jetzt stehe ich allerdings vor dem Problem das ich gerade keien Idee habe wie man Einstellungen am besten verwaltet ohne dabei die bisher sauber getrennten Klassen wieder "verunstalten" zu müssen.

Folgendes Scenario:

Delphi-Quellcode:
Klasse A:
  property enableHighlighting: boolean read FenableHighlighting write FenableHighlighting;
  property enableLog: boolean read FEnableLog write FEnableLog;

Klasse B:
  property autoOpen: boolean read FautoOpen write FautoOpen;
Im Hauptformular wird jeweils eine Instanz von KlasseA und KlasseB erzeugt. Zusätzlich erzeugt das Hauptformular dynamisch ein Einstellungs-Form.

Variante 1: Damit das Einstellungsformular direkt Änderungen an den settings der Objekte vornehmen kann müssten diese im Einstellungs-Form bekannt sein, sprich das Einstellungsform müsste auf die Objektinstanzen im Hauptformular zugreifen können -> unschön, abhängigkeiten usw.

Variante 2: Das Einstellungsformular mit getter und setter für die jeweiligen Objekte versehen und die Objekte dann sozusagen zur Laufzeit an die Einstellungs-Form übergeben -> fühlt sich auch merkwürdig an

Variante 3: Das Einstellungs-Fenster als reines Eingabe-Fenster benutzen, sprich getter und setter für die ganzen Checkboxen, Edit, ... und dann im Hauptformular die Werteübergabe an die verschiednene Objekte machen -> bläht den Code im Hauptformular ziemlich stark auf

Mir fallen noch ein paar weitere Varianten ein die sind aber auch nicht besser als die oben genannten.

Wie würdet ihr das sauber lösen ?

BUG 27. Okt 2014 22:06

AW: Programmeinstellungen organisieren
 
Ich finde Variante 1 gar nicht so schlimm, wenn klar ist, wem die Objekte gehören: dem Hauptformular. Das Einstellungsformular wird nach den Objekten erstellt und bekommt Referenzen darauf im Konstruktor übergeben. Das Hauptformular zerstört die Objekte erst wieder, wenn es bereits das Einstellungsformular zerstört hat.

EDIT: Ich merk gerade, das man Variante 1 auch anders interpretieren kann. Das Einstellungsformular sollte keine Abhängigkeit von dem Hauptformular haben, sondern nur von den beiden Einstellungsobjekten.

Sir Rufo 27. Okt 2014 22:28

AW: Programmeinstellungen organisieren
 
Einfach ein Repository für die Einstellungen
Delphi-Quellcode:
ISettingsRepository = interface
  function GetBool( const Section, Ident : string; Default : Boolean = False ) : Boolean;
  procedure SetBool( const Section, Ident : string; Value : Boolean );
  ...
end;
und konkretisieren für wo auch immer man das speichern möchte (INI, Registry, Datenbank, ...)

Dieses Repository gibt man dann einfach den Einstellungs-Klassen mit
Delphi-Quellcode:
TKlasseA = class
private
  FSettingsRepository : ISettingsRepository;
  FSection : string; // Path + ClassName?? Wie auch immer organisieren
  function Get_enableHighlighting : Boolean;
  procedure Set_enableHighlighting( Value : Boolean );
public
  constructor Create( SettingsRepository : ISettingsRepository; const Path : string );
  property enableHighlighting: boolean read Set_enableHighlighting write Get_enableHighlighting;
  ...
end;

function TKlasseA.Get_enableHighlighting : Boolean;
begin
  Result := FSettingsRepository.GetBool( FSection, 'enableHighlighting' );
end;

procedure TKlasseA.Set_enableHighlighting( Value : Boolean );
begin
  FSettingsRepository.SetBool( FSection, 'enableHighlighting', Value );
end;
Für den Einstellungsdialog hat man nun Zugriff auf das Repository und zwar völlig unabhängig von den einzelnen Klassen.

Blamaster 28. Okt 2014 12:44

AW: Programmeinstellungen organisieren
 
Das würde aber bedeuten das ich dieses Interface so in jeder Klasse implementieren müsste für die in irgendeiner Form Einstellungen gespeichert werden müssen.

Das widerspricht aber dem reuse/modularen Gedanken. Zum einen würde ich dem Anweder der ClassA aufzwingen wie er das speichern/behandeln von settings zu machen hat, zum anderen müsste ich Fremdklassen die das Interface nicht implementieren entweder dahingehend abändern oder eine Wrapperklasse drüber setzen. Da könnte man dann auch gleich ein großes Settingsobjekt erstellen und per Constructor sowohl an die KlasseA, KlasseB und das Einstellungsformular übergeben. (Genau das ist aber hinsichtlich der Trennung vom eigentlichen Objekt und dem speichern/verwalten von Einstellungen nicht gewollt)

Sir Rufo 28. Okt 2014 13:21

AW: Programmeinstellungen organisieren
 
Zitat:

Zitat von Blamaster (Beitrag 1277699)
Das würde aber bedeuten das ich dieses Interface so in jeder Klasse implementieren müsste für die in irgendeiner Form Einstellungen gespeichert werden müssen.

Äh, wie, nee ... du benutzt das Interface in jeder Einstellungsklasse implementiert wird das nur einmal.

Und die Einstellungen hast du doch auch nicht pro Klasse in einer Datei vorliegen, oder doch?

Blamaster 28. Okt 2014 14:57

AW: Programmeinstellungen organisieren
 
Hi,

was ist bei dir die genaue Definition von Einstellungsklasse ?

Nehmen wir besser ein anschauliches Beispiel. Wir haben eine Klasse die eine Datenbankverwaltung enthält und nennen die Klasse "TMyDatabase" diese Klasse hat jetzt die propertys "databaseName" und "databasePassword". Das sind die beiden Einstellungen die von "außen" also außerhalb der Klasse TMyDatabase gespeichert werden sollen.

Das speichern soll über Einträge in einer "settings.ini" erfolgen.

Eine Instanz also ein Objekt von TMyDatabase wird jetzt im constructor des Hauptformular "frmMain" erzeugt und im destructor wieder freigegeben.

Über ein eigenständiges Einstellungsfenster soll mithilfe von 2 Editfeldern nun das Passwort und der Datenbankname im Datenbankobjekt gesetzt werden.

Durch obiges Beispiel entstehen jetzt 2 Fragen/Probleme:
1. Wie werden die Daten der Editfelder im Einstellungsformular an die konkrete Instanz von TMyDatabase übergeben welche ja in frmMain erzeugt wurde und somit im Einstellungsformular erstmal nicht bekannt ist
2. Wie kann das speichern der Einstellungswerte außerhalb des TMyDatabase Objekt erfolgen.

Wenn ich es richtig verstanden habe würdest du bei dem vorgeschlagenen Ansatz nun in TMyDatabase das Interface "ISettingsRepository" einbinden. Das Einstellungsformular kennt dann lediglich das Interface ISettingsRepository nicht aber die Instanz oder überhaupt die Klasse TMyDatabase.

Das würde ja aber bedeuten das ich das Interface ISettingsRepository in der TMyDatabase Klasse einbinden müsste.

Und an der Stelle geht dann doch der Gedanke unabhängiger Module verloren. Der Sinn objektorientiert zu programmieren ist doch sinvolle Dinge zu einer Klasse zusammen zu führen unter anderem mit dem Hintergedanken der Wiederverwendbarkeit. (Kapselung in eigenständige unahängige Module)

Würde ich jetzt ISettingsRepository in TMyDatabase implementieren und die Klasse anschließed an einen Kollegen/Mitarbeiter/Community/Opensource weitergeben, dann zwinge ich den nachfolgenden Anweder das ISettingsRepository zu verwenden und zwar unabhängig davon wie er in seinem bisherigen Projekt in dem die Klasse nun eingesetzt werden soll das speichern der Einstellungen realisiert wurde.

Oder um es weiter zu führen neben TMyDatabase verwende ich zusätzlich die Fremdkomponente "TVirtualStringTree". Spezifische Einstellungen von VirtualStringTree sollen nun ebenfalls gespeichert werden. Das würde doch konkret bedeuten das ich auch in der fremden Klasse ISettingsRepository einbinden müsste und diese dem Interface auch genügen müsste.

Sir Rufo 28. Okt 2014 15:02

AW: Programmeinstellungen organisieren
 
Dann zeig doch mal wie du das bisher machst ... dann kann ich dir die Unterschiede so erläutern, dass du es auch verstehst :)

Also zeige doch einmal konkret an dem Beispiel von
Delphi-Quellcode:
TMyDatabase
und dem
Delphi-Quellcode:
TVirtualStringTree
wie du da aktuell die Einstellungen speicherst.

Ich hoffe ja nicht, dass du überall verteilt sowas wie
Delphi-Quellcode:
TIniFile.Create('xxx.ini');
stehen hast.

Blamaster 28. Okt 2014 16:02

AW: Programmeinstellungen organisieren
 
Okay hier ein Beispiel mit Code.

frmMainU:
Delphi-Quellcode:
unit frmMainU;

interface

uses
  frmSettingsU, DatabaseU, VirtualTrees, IniFiles, ....;

type
  TfrmMain = class(TForm)
    btnSettings: TButton;
    vst: TVirtualStringTree;
    procedure btnSettingsClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;
  database: TMyDatabase;

implementation

{$R *.dfm}

procedure TfrmMain.btnSettingsClick(Sender: TObject);
var
  frmSettings: TfrmSettings;
begin
  frmSettings := TfrmSettings.Create(nil);
  try
    frmSettings.ShowModal;
  finally
    frmSettings.Free;
  end;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
var
  ini: TInifile;
begin
  database := TMyDatabase.Create;

  ini := TIniFile.Create('settings.ini');
  try
    database.databasePassword := ini.ReadString('Database', 'password', '');
    database.databaseName := ini.ReadString('Database', 'name', '');
    vst.Enabled := ini.ReadBool('VST', 'enable', true);
  finally
    ini.Free;
  end;
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
  database.Free;
end;

end.
frmSettingsU:
Delphi-Quellcode:
unit frmSettingsU;

interface

uses
  IniFiles, ...;

type
  TfrmSettings = class(TForm)
    edtPassword: TEdit;
    edtDatabasName: TEdit;
    btnClose: TButton;
    chkvstEnable: TCheckBox;
    procedure btnCloseClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmSettings: TfrmSettings;

implementation

uses
  frmMainU;

{$R *.dfm}

procedure TfrmSettings.btnCloseClick(Sender: TObject);
begin
  Close;
end;

procedure TfrmSettings.FormCreate(Sender: TObject);
var
  ini: TInifile;
begin
  ini := TIniFile.Create('settings.ini');
  try
    edtPassword.Text := ini.ReadString('Database', 'password', '');
    edtDatabasName.Text := ini.ReadString('Database', 'name', '');
    chkvstEnable.Checked := ini.ReadBool('VST', 'enable', true);
  finally
    ini.Free;
  end;
end;

procedure TfrmSettings.FormDestroy(Sender: TObject);
var
  ini: TInifile;
begin
  database.databaseName := edtDatabasName.Text;
  database.databasePassword := edtPassword.Text;
  frmMain.vst.Enabled := chkvstEnable.Checked;

  ini := TIniFile.Create('settings.ini');
  try
    ini.WriteString('Database', 'password', edtPassword.Text);
    ini.WriteString('Database', 'name', edtDatabasName.Text);
    ini.WriteBool('VST', 'enable', chkvstEnable.Checked);
  finally
    ini.Free;
  end;
end;

end.
DatabaseU:
Delphi-Quellcode:
unit DatabaseU;

interface

type
  TMyDatabase = class(TObject)
  private
    FDatabaseName: string;
    FDatabasePassword: string;
  public
    property databaseName: string read FDatabaseName write FDatabaseName;
    property databasePassword: string read FDatabasePassword write FDatabasePassword;
  end;

implementation

end.

Bjoerk 28. Okt 2014 16:51

AW: Programmeinstellungen organisieren
 
Sind doch sehr einfache Klassen? Wenn andere Klassen oder Formulare eine Instanz davon bekommen sollen dann kann man z.B. die über den constructor mitschicken. Bei Formularen würde ich allerdings empfehlen, dann das Formular nicht automatisch zu erstellen sondern in FormCreate des Hauptformulars.

Beispiel:

Delphi-Quellcode:
  TVstSettings = class
  private
    FEnabled: boolean;
  public
    property Enabled: boolean read FEnabled write FEnabled;
    procedure LoadFromFile(const FileName: string);
    procedure SaveToFile(const FileName: string);
    procedure Clear;
  end;

  TDatabaseSettings = class
  private
    FName: string;
    FPassword: string;
  public
    property Name: string read FName write FName;
    property Password: string read FPassword write FPassword;
    procedure LoadFromFile(const FileName: string);
    procedure SaveToFile(const FileName: string);
    procedure Clear;
  end;

  TSomeForm = class(TForm)
  private
    FDatabaseSettings: TDatabaseSettings;
  public
    constructor Create(AOwner: TComponent; Value: TDatabaseSettings); reintroduce; overload;
  end;

  TMainForm = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FDatabaseSettings: TDatabaseSettings;
  end;

constructor TSomeForm.Create(AOwner: TComponent; Value: TDatabaseSettings);
begin
  inherited Create(AOwner);
  FDatabaseSettings := Value; // Kopplung;
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  FDatabaseSettings := TDatabaseSettings.Create;
  SomeForm := TSomeForm.Create(Self, FDatabaseSettings);
end;

Blamaster 29. Okt 2014 09:35

AW: Programmeinstellungen organisieren
 
@Bjoerk

danke so werde ich es jetzt erstmal machen :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:32 Uhr.
Seite 1 von 2  1 2      

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