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 ?