Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   dynamische Event "Liste" von Events? (https://www.delphipraxis.net/166218-dynamische-event-liste-von-events.html)

Jonas Shinaniganz 3. Feb 2012 10:17

dynamische Event "Liste" von Events?
 
:?

In meiner Unit wird ein Event(A) aufgerufen welches einige weitere Methoden aufruft.

Auf dem Weg zu diesem Event(A) werden einige Enscheidungen getroffen und je nachdem sollen in dem Event(A) Methoden hinzugefügt oder gelöscht werden.

Das hinzufügen oder löschen soll zur Runtime erfolgen.

So inetwa könnte man mein Problem formulieren. Leider fehlt mir der Ansatz... als Stichwort habe Ich EventHandler gesucht aber bin nur auf für mich unverständliches gestoßen :oops:

Hat jemand einen Codeschnippsel mit dem Ich weitermachen kann?

neo4a 3. Feb 2012 10:45

AW: dynamische Event "Liste" von Events?
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1149007)
In meiner Unit wird ein Event(A) aufgerufen welches einige weitere Methoden aufruft.

Auf dem Weg zu diesem Event(A) werden einige Enscheidungen getroffen und je nachdem sollen in dem Event(A) Methoden hinzugefügt oder gelöscht werden.

Ist das Abarbeiten der Methodenliste in Event(A) statisch (d.h. Anzahl und Reihenfolge der Methodenaufrufe ist konstant), dann gnügt es m.E., dem Event ein Record als Parameter mitzugeben, dessen Members "unterwegs" gesetzt werden.

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.

Jonas Shinaniganz 3. Feb 2012 11:40

AW: dynamische Event "Liste" von Events?
 
Zitat:

Zitat von neo4a (Beitrag 1149012)
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.

Wie erstelle Ich eine Solche Liste, füge Referenzen hinzu, lösche die Referenzen und führe die Liste dann aus?

gruß

neo4a 3. Feb 2012 12:28

AW: dynamische Event "Liste" von Events?
 
Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1149024)
Zitat:

Zitat von neo4a (Beitrag 1149012)
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 ;)

Zitat:

Zitat von Jonas Shinaniganz (Beitrag 1149024)
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.

Jonas Shinaniganz 3. Feb 2012 13:25

AW: dynamische Event "Liste" von Events?
 
Okay das ist schon wirklich ein Hammer und kann warscheinlich um EINGIES mehr als nötig.

Gibt mir dafür mal bis morgen ;)


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:09 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