Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Interfaces und Listen (Observer Pattern) (https://www.delphipraxis.net/129165-interfaces-und-listen-observer-pattern.html)

Zwoetzen 13. Feb 2009 19:09


Interfaces und Listen (Observer Pattern)
 
Hi DP'ler

folgende Situation:
In meinem Programm habe ich eine gewisse Speicherstruktur. Später möchte ich diese Struktur auch graphisch darstellen, sodass ich auf Änderungen innerhalb der Struktur reagieren muss. Kürzlich habe ich etwas über das Observer Pattern in einer Vorlesung gehört (lohnt sich doch, anwesend zu sein :mrgreen: ), und wollte dies nun verwenden.

Das ganze soll dabei auch mit Interfaces erstellt werden... Einfach weil ich noch nie damit gearbeitet habe ^^ Und da ist das Problem: Ich weiß nicht so recht, wie ich das anstellen muss.

Also am besten erstmal einen Happen Code:

Typdeklarationen:
Delphi-Quellcode:
type
  // Das Observer-Interface
  IObserver = interface
    procedure Update; // Reicht vorerst
  end;

  // Zwei Observer-Klassen, die dieses Interface implementieren, und die später dann bei Änderungen angeschupst werden sollen
  // (Implementieren eben das Interface)
  TObserver = class(TInterfacedObject, IObserver)
    procedure Update;
  end;
  TObserver2 = class(TInterfacedObject, IObserver)
    procedure Update;
  end;

  // Klasse des zu beobachtenden Objektes
  TSubject = class
  strict private
    FObservers: TList; // Liste der "registrierten" Observer
    FValue: String;
    procedure SetValue(const Value: String);
  public
    // Ein Test Value, der bei Änderung die Observer benachrichtigen soll
    property Value: String read FValue write SetValue;

    procedure Attach(O: IObserver);
    procedure Detach(O: IObserver);
    constructor Create;
    destructor Destroy; override;
  end;

var
  GSubject: TSubject;
Und noch ein Happen von den Promblemstellen in der Implementierung von TSubject:
Delphi-Quellcode:
procedure TSubject.Attach(O: IObserver);
begin
  FObservers.Add(O); //<--- ??? Was muss hier hin?
end;

procedure TSubject.Detach(O: IObserver);
begin
  FObservers.Remove(O); //<-- ??? Was muss hier hin?
end;

// Das benachrichtigen der Observer findet noch direkt im Setter statt,
// wird später natürlich ausgelagert und von jedem Setter aufgerufen
procedure TSubject.SetValue(const Value: String);
var
  I: Integer;
begin
  if FValue <> Value then begin
    FValue := Value;
    Form1.Memo1.Lines.Add('Value changed.');

    // Observer updaten
    for I := 0 to FObservers.Count - 1 do
      (FObservers[I] as IObserver).Update; //<-- ??? Und wie muss diese Zeile aussehen?
  end;
end;
Die Stellen, wo ich Probleme hab, sind auch im Quelltext markiert:
  • Wie füge ich die Observer zur Liste hinzu bzw. wie entferne ich sie wieder? (Attach() und Detach())
  • Wie rufe ich beim Durchlauf durch die Liste die Update-Methode der Observer auf?
  • Die obligatorische Frage: Ist diese Vorgehensweise richtig so oder sollte ich etwas anders machen? ^^

Würde mich freuen, wenn mir jemand helfen kann :)

MfG Zwoetzen

Apollonius 13. Feb 2009 19:17

Re: Interfaces und Listen (Observer Pattern)
 
Du solltest statt der TList eine TInterfaceList verwenden. Daneben solltest du deinem Interface eine GUID verpassen (unter die Zeile IObserver = interface gehen und strg + shift + g drücken).

Zwoetzen 13. Feb 2009 19:33

Re: Interfaces und Listen (Observer Pattern)
 
Danke für die Antwort, das mit der TInterfaceList war schonmal ein Schritt in die rihtige Richtung: Grundlegend funktioniert das Ganze jetzt, aber noch nicht ganz.

(Bis auf der Typ der Liste und der GUID wurde nichts am Quelltext verändert).

Nun das Problem:
Delphi-Quellcode:
// Obs1: TObserver wurde ordnungsgemäß angelegt
GSubject.Attach(Obs1);
GSubject.Detach(Obs1);
GSubject.Attach(Obs1);
GSubject.Detach(Obs1); // <<-- 'Ungültige Zeigeroperation' (Genauer gesagt bei der end;-Anweisung von Detach())
Und auch beim Beenden des Programms erscheinen teilweise Zugriffsverletzungen, die ich mir nicht erklären kann
(zb bei Adresse 02200007, Schreiben von 004F0804)


MfG Zwoetzen

Uwe Raabe 13. Feb 2009 19:49

Re: Interfaces und Listen (Observer Pattern)
 
Bei TInterfaceList-Instanzen muss man sehr vorsichtig sein. TInterfaceList ist nämlich selbst reference counted und die Instanz (in deinem Fall das Feld) sollte vom Typ IInterfaceList sein, sonst kann es zu ganz merkwürdigen Sachen kommen.

Delphi-Quellcode:
...
private
  FObservers: IInterfaceList;
...
constructor TSubject.Create;
begin
  inherited;
  FObservers := TInterfaceList.Create;
end;
...
destructor TSubject.Destroy;
begin
  FObservers := nil; // no .Free on Interfaces!
  inherited;
end;

Hawkeye219 13. Feb 2009 20:40

Re: Interfaces und Listen (Observer Pattern)
 
Hallo,

vermutlich ist die Variable Obs1 als TObserver vereinbart (statt IObserver) und sie wird nach dem ersten Detach-Aufruf automatisch freigegeben, weil ihr Referenzzähler auf 0 heruntergezählt wurde. Ein gemischter Zugriff über Objekt- und Interface-Referenzen ist immer sehr heikel.

Gruß Hawkeye

Zwoetzen 14. Feb 2009 09:46

Re: Interfaces und Listen (Observer Pattern)
 
Danke für die Antworten :)

Nachdem ich nun sowohl den Typ der Liste als auch der Observer auf das Interface geändert habe, laufen erste Tests ohne Fehler durch :)


Aber ich bin auch etwas verwirrt:
Ich habe ja jetzt zB die Observer als "Obs: IObserver" angelegt. Wieso kann ich das jetzt aber mit Obs := TObserver.Create anlegen? Weil da weis ich doch eigentlich einen Klassentyp einem Interfacetyp zu, oder nicht? :gruebel:

Und: Wann genau muss ich statts dem Typ das Interface in der Deklaration verwenden? Kann man da sagen, das man generell das Interface vorziehen sollte? Oder ist das nur hier im Zusammenhang mit der InterfaceList wichtig, dass die entsprechenden Objekte ein Interface als Typ haben?


MfG Zwoetzen

Hawkeye219 14. Feb 2009 10:43

Re: Interfaces und Listen (Observer Pattern)
 
Hallo,

eine sehr schöne Einführung in Interfaces findest du auf dieser Seite.

Gruß Hawkeye

Zwoetzen 16. Feb 2009 10:46

Re: Interfaces und Listen (Observer Pattern)
 
Danke Hawkeye, die Seite erklärt wirklich recht gut die Interfaces, hat gut zum Verständnis beigetragen ^^

MfG Zwoetzen


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:06 Uhr.

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