![]() |
Delphi-Version: XE5
Wie töte ich ein TAggregatedObject?
Liste der Anhänge anzeigen (Anzahl: 1)
Denksport-Aufgabe am frühen Morgen.
Ich habe eine Klasse (nennen wir sie
Delphi-Quellcode:
) welche die Realisierung eines Interfaces (
TMonsterklasse
Delphi-Quellcode:
) an eine andere Klasse (
IMyInterface
Delphi-Quellcode:
) delegieren soll.
TMyInterfaceDelegate
Je nachdem was man haben möchte, leitet man
Delphi-Quellcode:
nun am besten von
TMyInterfaceDelegate
Delphi-Quellcode:
oder
TAggregatedObject
Delphi-Quellcode:
ab. Zur Erinnerung: Ersteres leitet alle
TContainedObject
Delphi-Quellcode:
-Anfragen auf sich wieder an die
_QueryInterface
Delphi-Quellcode:
zurück,
TMonsterklasse
Delphi-Quellcode:
nicht. Beide reichen aber die ARC-Methoden
TContainedObject
Delphi-Quellcode:
und
_AddRef
Delphi-Quellcode:
an
_Release
Delphi-Quellcode:
zurück.
TMonsterklasse
Und wo ist nun die Frage? Folgendes: Im Destruktor meiner TMonsterklasse bekomme ich das aggregierte
Delphi-Quellcode:
nicht freigegeben da ich es mir in TMonsterklasse nur als Interface-Referenz vom Typ
TMyInterfaceDelegate
Delphi-Quellcode:
merke.
IMyInterface
Das einmal als Bild im Anhang und im Folgenden als Delphicode:
Delphi-Quellcode:
Interessante Teile der Implementation sind
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;
Delphi-Quellcode:
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
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;
Delphi-Quellcode:
) zu hinterlegen. Meine Idee wäre, die Referenz immerhin noch vom Typ
TMyInterfaceDelegate
Delphi-Quellcode:
zu halten. Die obige Implementation verkürzt sich somit auf
TAggregatedObject
Delphi-Quellcode:
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?
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; |
AW: Wie töte ich ein TAggregatedObject?
Da TAggregatedObject nicht über die Referenzzählung freigegeben wird, spricht nichts gegen eine lokale Instanz der entsprechenden Klasse innerhalb deiner Monster-Klasse. Da die Monster-Klasse für die Freigabe der Instanz verantwortlich ist, entspricht das auch dem gewünschten Design.
Gegen eine Speicherung in einer Interface-Variable spricht, daß du dir damit eine unerwünschte Referenzzählung einhandelst, die ein Freigeben der Monster-Instanz eigentlich verhindert, was du ja auch mit dem self._Release ausgleichst (müffelt halt etwas). Es ist auch durchaus korrekt, wenn du das Feld als
Delphi-Quellcode:
deklarierst. Damit kannst du deine
mySubInterfaceDelegate: TMyInterfaceDelegate
Delphi-Quellcode:
Funktion nämlich fasst so belassen wie sie ist.
getMyInterfaceDelegate
Grundsätzlich (sprich: ich kenne bisher keine Ausnahme) kann man sagen, daß bei zusammengesetzten Objekten mit
Delphi-Quellcode:
und
TAggregatedObject
Delphi-Quellcode:
immer die passenden Klassen als lokale Felder deklariert werden sollten.
TContainedObject
Der explizite
Delphi-Quellcode:
-Aufruf sollte bei einem selbst schon eine Warnung auslösen daß etwas nicht korrekt ist. In Delphi werden
_Release
Delphi-Quellcode:
und
_AddRef
Delphi-Quellcode:
eher selten direkt aufgerufen.
_Release
|
AW: Wie töte ich ein TAggregatedObject?
Ich wusste doch, auf den Spezialisten zu diesem Gebiet kann ich mich verlassen :love:
Dann ist schon mal sehr sicher, dass man die einzelnen Bausteine als Klassenreferenzen, nicht als Interface anspricht. Meine Motivation, als Typ eine Basisklasse möglichst weit oben (z.B.
Delphi-Quellcode:
) zu nehmen war, dass ich so auch schnell die Klasse austauschen kann bzw. einfach etwas anderes aus einer Factory kommt.
TAggregatedObject
Andererseits sind es ja nur sehr wenige Stellen die man anfassen müsste, wollte man die verwendete Klasse komplett austauschen. Ich werde da mal drüber schlafen... Vielen Dank für die Antwort :thumb: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz