Einzelnen Beitrag anzeigen

Der schöne Günther

Registriert seit: 6. Mär 2013
6.112 Beiträge
 
Delphi 10 Seattle Enterprise
 
#1

Wie töte ich ein TAggregatedObject?

  Alt 10. Dez 2013, 11:17
Delphi-Version: XE5
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?
Miniaturansicht angehängter Grafiken
klassendiagramm_mit-weissem-hintergrund.png  

Geändert von Der schöne Günther (10. Dez 2013 um 11:21 Uhr) Grund: Klassendiagramm nicht mehr transparent
  Mit Zitat antworten Zitat