Einzelnen Beitrag anzeigen

Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.299 Beiträge
 
Delphi 10.3 Rio
 
#1

Observer-Pattern Implementation

  Alt 10. Nov 2016, 14:40
Im Zuge eines etwas größeren Projekts, hat mich stahli (dicken Dank für deine Gedult und Mühe an der Stelle) auf die Idee gebracht, für meine Anwendung das Observer-Pattern zu nutzen.

Dazu hatte ich einige Vorraussetzungen:

a) Die Implementierung der notwendigen Funktionen sollte möglichs eigentständig sein

Da einiges an Objekten zusammenkommt, wollte ich vermeiden, jedesmal das gleiche
zu machen. Andererseits müssen bei den Unterschiedlichen konkreten Objekten
aber auch unterschiedliche Daten übertragen werden.

b) Da das o.g. Projekt später auch über ein Plugin-System erweiterbar werde wird,
muss auch gewährleistet sein, das ich ggf. Elemente aus einer externen DLL bekomme.


b heißt also Interfaces, da das der mir einzig bekannte Weg ist, sowas wie Objekte
aus einer DLL zu bekommen, bzw anzusprechen.

a heißt, Basisklassen die die Daten als Pointer liefern.

Hier will ich nu meine Implementation präsentieren:

Interface

Delphi-Quellcode:
TYPE
  ISubject = INTERFACE;

  IListener = INTERFACE
    Procedure RegisterMe(Const aSubject:ISubject);
    Procedure UnregisterMe(Const aSubject:ISubject);
    procedure Notification(const data:Pointer);
  END;

  ISubject = Interface
     Procedure RegisterListener(const obj:IListener);
     Procedure UnregisterListener(Const obj:IListener);
     Procedure NotifyListener(const data : Pointer);
  End;
Basisklassen:

Delphi-Quellcode:
unit BaseClasses;

interface
uses
  windows,classes,contnrs,BaseInterfaces;

TYPE
  TBaseSubject = class;

  TBaseListener = class(TInterfacedPersistent,IListener)
  private
  protected
  published
  public
    Procedure RegisterMe(Const aSubject:ISubject);
    Procedure UnregisterMe(Const aSubject:ISubject);
    //Wird erst in der Ableitung befüllt.
    procedure Notification(const data:Pointer);virtual;abstract;
  end;

  TBaseSubject = Class(TInterfacedPersistent,ISubject)
  PRIVATE
     flist : TList;
     procedure ClearList;
  PROTECTED
  PUBLISHED
     Constructor Create;
     Destructor Destroy;override;
  PUBLIC
     Procedure RegisterListener(Const obj:IListener);
     Procedure UnregisterListener(Const obj:IListener);
     Procedure NotifyListener(const data : Pointer);
  End;

implementation

{ TBaseListener }

procedure TBaseListener.RegisterMe(aSubject: ISubject);
begin
  aSubject.RegisterListener(self);
end;

procedure TBaseListener.UnregisterMe(aSubject: ISubject);
begin
  aSubject.UnregisterListener(self);
end;

{ TBaseSubject }

procedure TBaseSubject.ClearList;
begin
  while (flist.count > 0) do
    flist.Delete(0);
end;

constructor TBaseSubject.Create;
begin
  flist := TList.create;
end;

destructor TBaseSubject.Destroy;
begin
  ClearList;
  flist.free;
  inherited;
end;

procedure TBaseSubject.NotifyListener(const data:pointer);
var
  i : integer;

begin
  for I := 0 to flist.count - 1 do
    IListener(flist.items[i]).Notification(data);
end;

procedure TBaseSubject.RegisterListener(obj: IListener);
begin
  flist.Add(Pointer(obj));
end;

procedure TBaseSubject.UnregisterListener(obj: IListener);
begin
  flist.Remove(Pointer(obj));
end;
und schließlich meine "Realen" Klassen aus dem Testprojekt:

Delphi-Quellcode:
uses
  windows,classes,BaseClasses;

TYPE

  TRealListener = Class(TBaseListener)
    PRIVATE
    PROTECTED
    PUBLIC
      procedure Notification(const data:pointer);override ;
    PUBLISHED
  End;

  TRealSubject = Class(TBaseSubject)
    PRIVATE
      fcaption : string;
    procedure setCaption(const Value: string);
    PROTECTED
    PUBLIC
    PUBLISHED
      property Caption:string read fcaption write setCaption;
  End;
implementation
uses
  unit28;

{ TRealListener }

procedure TRealListener.Notification(const data: pointer);
begin
  form28.memo1.lines.append(string(data^));
end;

{ TRealSubject }


procedure TRealSubject.setCaption(const Value: string);
begin
  fcaption := Value;
  NotifyListener(@fcaption);
end;

end.
(unit28 is lediglich die Form der Application mit Buttons und einem Memo drauf )

Außer dem Einsatz von Generics, fällt mir im Moment keine Optimierung mehr ein (und da ich
Turbo Delphi einsetze, geht das im Moment nicht )

Was haltet ihr davon ?
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat