Einzelnen Beitrag anzeigen

Benutzerbild von weltaran
weltaran

Registriert seit: 12. Sep 2003
Ort: Offenburg
78 Beiträge
 
Delphi 5 Enterprise
 
#1

Problem mit Observer-Pattern

  Alt 20. Mai 2005, 20:21
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:
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.
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!

Ciao

weltaran
  Mit Zitat antworten Zitat