![]() |
Problem mit Observer-Pattern
Hallo Leute!
Ich hab auf der Seite von Joanna Carter das (meines Erachtens sehr gute) Tutorial gelesen. Dennoch habe ich Probleme damit. Der ClockTimer wird einfach so zerstört, ohne das ich dies explizit befohlen habe. Das schein mit der Interface Referenzzählung zusammenzuhängen, aber ganau steig ich da nicht dahinter. Sorry, dass ich euch da so`n Brocken Code da hinklatsche. Ich tippe stark auf die Notify-Methode, hier müsste der Hund begraben liegen. Ach ja: Ich hab IInterface (kennt mein D5 nicht) durch IUnknown ausgetauscht. Könnte das der Fehler sein?
Delphi-Quellcode:
Nchtrag: wenn ich die Kommentarzeichen vor ShowMessage wegmache läuft der Zähler los, aber nur wenn ich nach dem Start etwas Zeit vergehen lasse, bis ich auf den Button drücke!
unit frmMain;
interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, extctrls, StdCtrls; type TClockTimer = class; TForm1 = class; TObservable = class; IClockTimer = interface; TDigitalClock = class; IObserver = interface; IObservable = interface; IObserver = interface ['{202BAB74-E7A6-4FEC-9F93-8D3EA8B07172}'] procedure obsUpdate(const Observable: IUnknown); end; IObservable = interface ['{31F285F0-B80B-479D-BC35-475E6ED8A148}'] procedure obsAddObserver(observer: IObserver); procedure obsDeleteObserver(observer: IObserver); procedure obsNotify; end; TForm1 = class(TForm) Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private fClockTimer: TClockTimer; fDigitalClock1: TDigitalClock; public end; TObservable = class(TInterfacedObject, IObservable) private fController: Pointer; fObservers: TInterfaceList; procedure obsAddObserver(Observer: IObserver); procedure obsDeleteObserver(Observer: IObserver); procedure obsNotify; public constructor Create(const Controller: IUnknown); end; IClockTimer = interface ['{9DC95238-36BD-4595-8DE2-B56579A51FC8}'] function GetTime: TDateTime; end; TClockTimer = class(TInterfacedObject, IClockTimer, IObservable) private fTimer: TTimer; fInternalTime: TDateTime; fObservable: IObservable; function GetTime: TDateTime; procedure Tick(Sender: TObject); property Observable: IObservable read fObservable write fObservable implements IObservable; public constructor Create; destructor Destroy; override; end; TDigitalClock = class(TPanel, IObserver) private procedure IObserver.obsUpdate = ObserverUpdate; procedure ObserverUpdate(const Observable: IUnknown); public end; var Form1: TForm1; implementation {$R *.DFM} // TObservable constructor TObservable.Create(const Controller: IUnknown); begin inherited Create; fController:= Pointer(Controller); end; procedure TObservable.obsAddObserver(Observer: IObserver); begin if not Assigned(fObservers) then begin fObservers:= TInterfaceList.Create; end; fObservers.Add(Observer); obsNotify; end; procedure TObservable.obsDeleteObserver(Observer: IObserver); begin if Assigned(fObservers) then begin fObservers.Remove(Observer); if fObservers.Count = 0 then begin fObservers.Free; end; end; end; procedure TObservable.obsNotify; var i: integer; myObserver: IObserver; myController: IUnknown; begin if Assigned(fObservers) then begin for i:= 0 to Pred(fObservers.Count) do begin myObserver:= IObserver(fObservers.Items[i]); myController:= IUnknown(fController); myObserver.obsUpdate(myController); end; end; end; // TClockTimer constructor TClockTimer.Create; begin inherited Create; fTimer:= TTimer.Create(nil); fTimer.Interval:= 1000; fTimer.OnTimer:= Tick; fTimer.Enabled:= true; fObservable:= TObservable.Create(self); end; destructor TClockTimer.Destroy; begin //ShowMessage('ClockTimer now destroying!'); fTimer.Enabled:= false; fTimer.Free; inherited Destroy; end; function TClockTimer.GetTime: TDateTime; begin Result:= fInternalTime; end; procedure TClockTimer.Tick(Sender: TObject); begin fInternalTime:= Now; fObservable.obsNotify; end; // TDigtalClock procedure TDigitalClock.ObserverUpdate(const Observable: IUnknown); var Obj: IClockTimer; begin Observable.QueryInterface(IClockTimer, Obj); if Assigned(Obj) then begin Caption:= FormatDateTime('tt', Obj.GetTime); end; end; procedure TForm1.FormCreate(Sender: TObject); begin fClockTimer:= TClockTimer.Create; fDigitalClock1:= TDigitalClock.Create(self); fDigitalClock1.Parent:= self; fDigitalClock1.Align:= alLeft; fDigitalClock1.Font.Size:= 14; fDigitalClock1.Font.Style:= [fsBold]; end; procedure TForm1.Button1Click(Sender: TObject); var myObservable: IObservable; myObserver: IObserver; begin myObservable:= IObservable(fClockTimer); myObserver:= IObserver(fDigitalClock1); myObservable.obsAddObserver(myObserver ); end; end. Ciao weltaran |
Re: Problem mit Observer-Pattern
OK, ich hab den Übeltäter jetzt eingekreist. Es handelt sich definitiv um die ObserverUpdate-Methode wenn ich folgenden Code
Delphi-Quellcode:
durch diesen ersetze
procedure TDigitalClock.ObserverUpdate(const Observable: IUnknown);
var Obj: IClockTimer; begin Observable.QueryInterface(IClockTimer, Obj); if Assigned(Obj) then begin Caption:= FormatDateTime('tt', obj.GetTime); end; end;
Delphi-Quellcode:
procedure TDigitalClock.ObserverUpdate(const Observable: IUnknown); var Obj: IClockTimer; begin //Observable.QueryInterface(IClockTimer, Obj); //if Assigned(Obj) then //begin Caption:= FormatDateTime('tt', Now); //end; end; , dann tut alles. Kann mir jemand erklären, was in dieser Funktion vor sich geht? Bisher habe ich 'QueryInterface' im Zusammenhang mit Schnittstellen noch nie gebraucht. Ist es so, dass ich damit das implementierende Objekt erzeugen kann ohne die Klasse zu kennen? Dann müsste doch in dem Moment, in dem QueryInterface ausgeführt wird auch das Create von TClockTimer ausgeführt werden. Dem scheint aber nicht so zu sein. Ich wäre für etwas Nachhilfe dankbar. Ciao Ciao |
Re: Problem mit Observer-Pattern
Du kommst bei der Referenzzählung etws durcheinander, d.h. fClockTimer wird dir zu früh zerstört.
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var myObservable: IObservable; myObserver: IObserver; begin myObservable:= fClockTimer; fClockTimer._AddRef; myObserver:= fDigitalClock1; myObservable.obsAddObserver(myObserver); end; |
Re: Problem mit Observer-Pattern
Super! Jetzt tut es.
Danke Ciao |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:27 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 by Thomas Breitkreuz