Einzelnen Beitrag anzeigen

Dejan Vu
(Gast)

n/a Beiträge
 
#11

AW: Programmeinstellungen organisieren

  Alt 29. Okt 2014, 16:24
Also ich würde eine TSettingsklasse schreiben, die die Einstellungen verwaltet, d.h. läd und speichert. Zusätzlich implementiert die Klasse noch das Observer-Pattern.

Wenn eine Form von Änderungen an einer oder allen Settings benachrichtigt werden möchte, dann meldet es sich bei der TSettings-Klase an, (z.B. im FormCreate oder über einen DI-Container). Und wenn so ein Formular beendet wird, meldet es sich wieder ab. Wenn mehrere Formulare Interesse haben, na dann melden sie sich eben auch an.

Die Settingsklasse hat also z.B. folgenden Aufbau:
Delphi-Quellcode:
Type
  ISettings = interface
    Property SomeSetting : String
  end;

  ISettingsListener = interface
     procedure SettingsChanged;
     Property Settings : ISettings;
  end;

  TSettings = class (ISettings)
    fListeners : TInterfaceList<ISettingsListener>;
  public
    procedure Subscribe (listener : ISettingsListener);
    Procedure UnSubscribe (listener : ISettingsListener);
    ...
    Property SomeSetting : String Read fSomeSetting Write SetSomeSetting;
  End;

Procedure TSettings.Subscribe (listener : ISettingsListener);
begin
  assert (fListeners.IndexOf(listener)= -1,'Cannot subscribe twice');
  fListeners.Add(listener);
End;

Procedure TSettings.UnSubscribe (listener : ISettingsListener);
begin
  assert (fListeners.IndexOf(listener)<>-1,'Cannot unsubscribe twice');
  fListeners.Remove(listeners);
end;

Procedure TSettings.SetSomeSetting (const value : String);
Begin
  if fSomeSetting=value then exit;
  fSomeSetting := value;
  NotifyListeners();
End;

Procedure TSettings.NotifyListeners;
Begin
  for listener in fListeners do listener.SettingsChanged;
End;
Jeder Propertysetter ruft 'NotifyListeners' auf, damit alle angemeldeten Listener auch von den Änderungen erfahren. Man kann das auch verfeinern, indem noch mitgeteilt wird, welche Property sich genau verändert hat. muss man aber nicht'.

Ein Formular, das benachtichtigt werden möchte, implementiert nun 'ISettingsListener' und reagiert auf die Änderungen der Einstellungen, wie es möchte. Dem Settingsformular wird einfach die eine Instanz von TSettings zum editieren übergeben.

Hat man unterschiedliche Einstellungen, macht man unterschiedliche Klassen.

So hat man eine komplette Trennung und kaschiert Abhängigkeiten nicht über das Aufstülpen eines Interfaces, wogegen aber eigentlich auch nichts zu sagen ist, außer vielleicht, das das keine (so) lose Kopplung mehr ist.

Ich finde die althergebrachte Observerlösung aber flexibler, eben weil man beliebige Listener/Observer anmelden kann. einen Logger z.B. der alle Änderungen protokolliert.

Woher bekommt ein Formular nun die Instanz einer 'TSettings'? Ich würde einen DI-Container bauen, und dem die Instantiierung der Klasse überlassen:

Delphi-Quellcode:
Procedure TMyDIContainer.CreateForm (aFormClass : TFormClass; Var aInstance : TForm);
Begin
  aInstance := aFormClass.Create;
  
  if aInstance is ISettingsListener then begin
    ISettingsListener (aInstance).Settings := settings;
    settings.Subscribe(ISettingsListener (aInstance));
  end;
end;
Man kann in der Factory auch noch andere Belegungen vornehmen. Vielleicht gibt es noch z.B. eine TDatabaseSettings-Klasse. Dann wären dann entsprechende Settings und Interfaces für und die Factory würde einfach prüfen, ob die Form das 'IDatabaseSettingsListener' Interface implementiert und dann das Datenmodul ranflanschen.

Sehr praktisch, variable und erhält die lose Kopplung.

Man kann dem Formular auch die Settings per Konstruktor übergeben, aber dann wächst die Parameterliste des Konstruktors immer weiter... Das ist dann nicht so skalierbar...
  Mit Zitat antworten Zitat