Einzelnen Beitrag anzeigen

neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#4

AW: dynamische Event "Liste" von Events?

  Alt 3. Feb 2012, 13:28
Im anderen Fall könnte es als Parameter eine Liste mit Methoden-Referenzen tun, die "unterwegs" gefüllt wird. Dann ist der Umfang und die Reihenfolge dynamisch und Event(A) muss noch nicht einmal die Methoden kennen.
Das 2te hört sich super an.
Das habe ich befürchtet

Wie erstelle Ich eine Solche Liste, füge Referenzen hinzu, lösche die Referenzen und führe die Liste dann aus?
Das Problem bei diesem Ansatz ist es, dass Du keine Kontrolle über die Laufzeit der Methoden hast. Praktisch kann es bedeuten, dass zum Zeitpunkt der Ausführung, dass Callback-Objekt, das für die Ausführung verantwortlich sein soll, gar nicht mehr existiert -> AV.

Um auf der sicheren Seite zu sein, habe ich mich des Observer-Patterns bedient. Dazu registrieren sich die Objekte in einer zentralen Liste (Singleton) mit den Events, über die sie benachrichtigt werden wollen. Wichtig ist, dass sie sich auch wieder deregistrieren, bevor sie zerstört werden.

In Deinem Event(A) werden nun die Events getriggert, von der Observerliste entgegen genommen, die dann ihrerseits alle registrierten Observer benachrichtigt, die dann entsprechend in ihren Callback-Methoden weiter arbeiten können. Klingt vielleicht etwas aufwändiger als es letztlich ist.

So könnte die Observer-Komponente aussehen:
Delphi-Quellcode:
unit uObserver;
{ Zur Nutzung muss der Client:
  1. das Interface IdcObserver implementieren

  2. die Methode DoOnObserverNotification() bereitstellen und dort
    auf das passende Interface prüfen:
    if Supports(aInterface, IdcLangMan) then

  3. sich als Observer un/registrieren:
    Create: RegisterObserver(Self);
    Destroy: UnregisterObserver(Self);
 
  Die Notification erfolgt durch Aufruf von
  NotifyObserver() mit der Interface-Referenz
}

interface

uses
  Classes, SysUtils;
type
  IdcObserver = interface
    ['{5308A18A-FE7C-4A60-BB4F-34B2B9F8AAEF}']
    procedure DoOnObserverNotification(aInterface : IInterface; aParams : TObject = nil);
  end;

procedure RegisterObserver(aObject : TObject);
procedure UnregisterObserver(aObject : TObject);
procedure NotifyObserver(aInterface : IInterface; aParamObject : TObject = nil);

implementation

uses
  Generics.Collections;

  procedure RegisterObserver(aObject : TObject);
  procedure UnregisterObserver(aObject : TObject);
  procedure NotifyObserver(aInterface : IInterface; aParamObject : TObject = nil);

{
  Die Items sind Referenzen auf die Komponenten, die IdcObserver implementieren.
  Items werden benachrichtigt und müssen selbst richtig darauf reagieren (s.o.).
}

  TdcObserList = TList<IdcObserver>;

  TdcObserverList = class(TInterfacedObject)
  private
    FObserverList : TdcObserList;
    procedure RegisterObserver(aObserver : IdcObserver);
    procedure UnregisterObserver(aObserver : IdcObserver);
    procedure NotifyObserver(aInterface : IInterface; aParamObject : TObject = nil);
  public
    constructor Create;
    destructor Destroy; override;
  end;

var
  aObserList : TdcObserverList;

procedure RegisterObserver(aObject : TObject);
var
  aObserver : IdcObserver;
begin
  if Supports(aObject, IdcObserver, aObserver) then
    aObserList.RegisterObserver(aObserver);
end;

procedure UnregisterObserver(aObject : TObject);
var
  aObserver : IdcObserver;
begin
  if Supports(aObject, IdcObserver, aObserver) then
    aObserList.UnregisterObserver(aObserver);
end;

procedure NotifyObserver(aInterface : IInterface; aParamObject : TObject = nil);
begin
  aObserList.NotifyObserver(aInterface, aParamObject);
end;

{ TdcObserverList }

constructor TdcObserverList.Create;
begin
  FObserverList := TdcObserList.Create;
end;

destructor TdcObserverList.Destroy;
begin
  FObserverList.Free;
  inherited;
end;

procedure TdcObserverList.NotifyObserver(aInterface : IInterface; aParamObject : TObject = nil);
var
  aObserver : IdcObserver;
begin
  for aObserver in FObserverList do
    aObserver.DoOnObserverNotification(aInterface, aParamObject);
end;

procedure TdcObserverList.RegisterObserver(aObserver: IdcObserver);
begin
  FObserverList.Add(aObserver);
end;

procedure TdcObserverList.UnregisterObserver(aObserver: IdcObserver);
begin
  FObserverList.Remove(aObserver);
end;

initialization
  aObserList := TdcObserverList.Create;

finalization
  FreeAndNil(aObserList);

end.
Ich habe das Sample aus einem Projekt von mir entnommen, wo der Observer selbst mittels Spring-DI verwaltet wird, was ich zur besseren Übersichtlichkeit entfernt habe. Insoweit können ggf. noch Anpassungen erforderlich sein. Aber vielleicht hilft es auch so.
Andreas

Geändert von neo4a ( 3. Feb 2012 um 14:11 Uhr)
  Mit Zitat antworten Zitat