Denksport-Aufgabe am frühen Morgen.
Ich habe eine Klasse (nennen wir sie
TMonsterklasse
) welche die Realisierung eines Interfaces (
IMyInterface
) an eine andere Klasse (
TMyInterfaceDelegate
) delegieren soll.
Je nachdem was man haben möchte, leitet man
TMyInterfaceDelegate
nun am besten von
TAggregatedObject
oder
TContainedObject
ab.
Zur Erinnerung: Ersteres leitet alle
_QueryInterface
-Anfragen auf sich wieder an die
TMonsterklasse
zurück,
TContainedObject
nicht. Beide reichen aber die ARC-Methoden
_AddRef
und
_Release
an
TMonsterklasse
zurück.
Und wo ist nun die Frage? Folgendes: Im Destruktor meiner TMonsterklasse bekomme ich das aggregierte
TMyInterfaceDelegate
nicht freigegeben da ich es mir in TMonsterklasse nur als Interface-Referenz vom Typ
IMyInterface
merke.
Das einmal als Bild im Anhang und im Folgenden als Delphicode:
Delphi-Quellcode:
IMyInterface = interface
['{62EB99E2-5762-41C2-AF46-D612B9BD5C01}']
procedure someProc();
end;
//TMyInterfaceDelegate = class(TContainedObject, ISubInterface)
TMyInterfaceDelegate = class(TAggregatedObject, IMyInterface)
public
// controller wäre dann eine TMonsterklasse-Instanz
constructor Create(const controller: IInterface);
destructor Destroy(); override;
procedure someProc();
end;
// Diese Klasse delegiert die Realisierung von IMyInterface an
// ein aggregiertes TMyInterfaceDelegate-Objekt
TMonsterklasse = class(TInterfacedObject, IMyInterface)
private var
mySubInterfaceDelegate: IMyInterface;
private
function getMyInterfaceDelegate(): IMyInterface;
public
constructor Create();
destructor Destroy(); override;
// Interface Delegation
protected property myInterfaceRealization: IMyInterface
read getMyInterfaceDelegate implements IMyInterface;
end;
Interessante Teile der Implementation sind
Delphi-Quellcode:
function TMonsterklasse.getMyInterfaceDelegate(): IMyInterface;
begin
if not Assigned(mySubInterfaceDelegate) then begin
mySubInterfaceDelegate := TMyInterfaceDelegate.Create(self);
// _AddRef auf myRealizer wird wieder an mich selbst delegiert!
// Da der RefCount sonst niemals Null wird, erniedrige ich ihn
// hier künstlich wieder um eins.
self._Release();
end;
Result := mySubInterfaceDelegate;
end;
destructor TMonsterklasse.Destroy();
begin
// Wie zerstöre ich nun mySubInterfaceDelegate?
// An den Referenzzähler komme ich nicht dran
// Ist es ein TContainedObject kann ich noch zu einer Klassenreferenz
// casten und dann den Destruktor aufrufen. Aber bei TAggregatedObject
// wird _QueryInterface an mich delegiert und ich kann nichtmals
// zu einer Klasse casten...
(mySubInterfaceDelegate as TContainedObject).Free();
end;
Wie man sieht, alles andere als schön. Ich möchte allerdings vermeiden, meine Referenz auf das aggregierte Objekt in der ganz konkreten Klasse (also vom Typ
TMyInterfaceDelegate
) zu hinterlegen. Meine Idee wäre, die Referenz immerhin noch vom Typ
TAggregatedObject
zu halten. Die obige Implementation verkürzt sich somit auf
Delphi-Quellcode:
destructor TMonsterklasse.Destroy();
begin
mySubInterfaceDelegate.Free();
end;
function TMonsterklasse.getMyInterfaceDelegate(): IMyInterface;
begin
if not Assigned(mySubInterfaceDelegate)
then
mySubInterfaceDelegate := TMyInterfaceDelegate.Create(self);
if not Supports(mySubInterfaceDelegate, IMyInterface, Result)
then
raise Exception.Create('
Ich habe keine Ahnung was dann geschehen soll');
end;
Hier fühle ich mich aber mit der letzten Methode nicht wohl. Aber immerhin funktioniert es und alles wird auch ordentlich freigegeben. Kann mir jemand gut zureden, dass ich alles richtig mache? Oder kann man etwas anders lösen?