Wo wäre der denn Vorteil der Generics hier?
Es ist nur eine interne Verbesserung (unabhängig vom Typ der "Observables"):
if Supports(ObserverCollection.Items[I], INotifyObserver, fIntf) then
entfällt, wenn die ObserverCollection mit INotifyObserver statt IInterface arbeitet.
Wenn man (wie der Code vermuten lässt) sicher stellen kann, daß sich nur INotifyObserver in die InterfaceList eintragen können, dann kann man das
Supports
auch durch ein einfaches
as
ersetzen. Somit reduziert sich die Methode auf:
Delphi-Quellcode:
procedure TObserverSubject.NotifyObservers;
var
I: Integer;
begin
for I := 0 to ObserverCollection.Count - 1 do
begin
(ObserverCollection.Items[I] as INotifyObserver).ObserverNotify(Self);
end;
end;
Richtig interessant für Generics wäre aber schon ein generisches Interface á la:
Delphi-Quellcode:
INotifyObserver<T> = interface
procedure ObserverNotify(Sender: T);
end;
Damit könnte dann eine einzige Klasse für unterschiedliche Subject-Typen mehrere ObserverNotify-Methoden in einer Klasse implementieren.
Leider scheitert dies aber erstmal daran, daß man einem generischen Interface bei der "Spezialisierung" (wenn man den generischen Typ auflöst) keine eigene
GUID mitgeben kann. Somit hat das Interface dann entweder
keine GUID oder immer die gleiche. Damit lassen sich dann aber auch keine (sinnvollen)
Supports
und
as
Aufrufe mehr damit machen.
Arbeitet man dann aber mit generischen Interfaces ohne
GUID muss zwangsläufig die ObserverCollection vom Typ TList<INotifyObserver<T>> sein.
Ergänzend dazu habe ich das Subject noch ausgelagert. Damit vermeidet man zum Einen, daß die Subject-Klasse von dem ObserverSubject abgeleitet werden muss, und zum Anderen könnte man die Subject-Instanz noch austauschbar machen, ohne die Observer zu deregistrieren und wieder zu registrieren.
Der ganze Code sähe dann so aus:
Delphi-Quellcode:
type
INotifyObserver<T> = interface
procedure ObserverNotify(Sender: T);
end;
TObserverSubject<T> = class
private
FSubject: T;
protected
ObserverCollection: TList<INotifyObserver<T>>;
public
constructor Create(ASubject: T);
destructor Destroy; override;
procedure RegisterObserver(Observer: INotifyObserver<T>);
procedure UnregisterObserver(Observer: INotifyObserver<T>);
procedure NotifyObservers();
property Subject: T read FSubject;
end;
constructor TObserverSubject<T>.Create(ASubject: T);
begin
ObserverCollection := TList<INotifyObserver<T>>.Create();
FSubject := ASubject;
end;
destructor TObserverSubject<T>.Destroy;
begin
ObserverCollection.Free;
inherited;
end;
procedure TObserverSubject<T>.NotifyObservers;
var
intf: INotifyObserver<T>;
begin
for intf in ObserverCollection do
begin
intf.ObserverNotify(Subject);
end;
end;
procedure TObserverSubject<T>.RegisterObserver(Observer: INotifyObserver<T>);
begin
ObserverCollection.Add(Observer);
end;
procedure TObserverSubject<T>.UnregisterObserver(Observer: INotifyObserver<T>);
begin
ObserverCollection.Remove(Observer);
end;
Ein Beispiel für eine mehrere Observer implementierende Instanz wäre z.B.:
Delphi-Quellcode:
type
TMyClient = class(TInterfacedObject, INotifyObserver<TComboBox>, INotifyObserver<TStrings>)
protected
procedure ObserverNotify(Sender: TComboBox); overload;
procedure ObserverNotify(Sender: TStrings); overload;
end;