ここで起こっていることはTContainer.Create
、オブジェクトのインスタンスを呼び出して作成することです。ただし、そのインスタンスをインターフェイス参照であるグローバル変数に割り当てますFoo
。その変数の型は であるためIFoo
、インターフェイス委譲は、実装オブジェクトが のインスタンスでTFooImpl
あり、 のインスタンスではないTContainer
ことを意味します。
したがって、 のインスタンスへの参照を取得するものTContainer
はなく、参照カウントが増加することはないため、破棄されることもありません。
これを回避する簡単な方法はないと思います。使用できるTAggregatedObject
かもしれませんが、問題が解決しない場合があります。あなたがしたくないと私が想像するTContainer.FFoo
タイプであると宣言することを強制するでしょう。TFooImpl
とにかく、これがそのように再キャストされたように見えるものです:
program SO16210993_TAggregatedObject;
{$APPTYPE CONSOLE}
type
IFoo = interface
procedure Foo;
end;
TFooImpl = class(TAggregatedObject, IFoo)
procedure Foo;
end;
TContainer = class(TInterfacedObject, IFoo)
private
FFoo: TFooImpl;
function GetFoo: IFoo;
public
destructor Destroy; override;
property Foo: IFoo read GetFoo implements IFoo;
end;
procedure TFooImpl.Foo;
begin
Writeln('TFooImpl.Foo called');
end;
destructor TContainer.Destroy;
begin
Writeln('TContainer.Destroy called');//this line does run
FFoo.Free;
inherited;
end;
function TContainer.GetFoo: IFoo;
begin
if not Assigned(FFoo) then
FFoo := TFooImpl.Create(Self);
Result := FFoo;
end;
procedure Main;
var
Foo : IFoo;
begin
Foo := TContainer.Create;
Foo.Foo;
end;
begin
Main;
Readln;
end.
ドキュメントはこれについて話します:
委任されたインターフェイスを実装するために使用するクラスは、TAggregationObject から派生する必要があります。
最初は、これに関するドキュメントが見つかりませんでしたTAggregationObject
。TAggregatedObject
そして最後に、実際に名前が付けられ、文書化されていることに気付きました。
TAggregatedObject は、IInterface メソッドを実装して制御 IInterface に委譲することにより、集約の内部オブジェクトに機能を提供します。
集約オブジェクトは、いくつかのインターフェース化されたオブジェクトで構成されるオブジェクトです。各オブジェクトは独自の動作とインターフェイスを実装しますが、すべてのオブジェクトは同じ参照カウント (コントローラー オブジェクトの参照カウント) を共有します。コンテナー パターンでは、コントローラーはコンテナー オブジェクトです。
TAggregatedObject 自体はインターフェイスをサポートしていません。ただし、集合体の典型であるように、集合体から派生するオブジェクトによって使用される IInterface のメソッドを実装します。したがって、TAggregatedObject は、集約の一部であるオブジェクトを作成するためのインターフェイスを実装するクラスのベースとして機能します。
TAggregatedObject は、包含オブジェクトと接続オブジェクトを作成するクラスのベースとして使用されます。TAggregatedObject を使用すると、IInterface メソッドの呼び出しが集約の制御 IInterface に委譲されるようになります。
制御 IInterface は TAggregatedObject のコンストラクターで指定され、Controller プロパティによって示されます。
さらに、ソースコードのコメントからこれがあります:
TAggregatedObject と TContainedObject は、外部の制御オブジェクトに集約または含まれることを意図したインターフェイス オブジェクトに適した基底クラスです。外側のオブジェクト クラス宣言のインターフェイス プロパティで "implements" 構文を使用する場合、これらの型を使用して内側のオブジェクトを実装します。
コントローラーに代わって集約されたオブジェクトによって実装されるインターフェイスは、コントローラーによって提供される他のインターフェイスと区別できません。集約されたオブジェクトは、独自の参照カウントを維持してはなりません。それらは、コントローラーと同じ有効期間を持つ必要があります。これを実現するために、集約されたオブジェクトは参照カウント メソッドをコントローラーに反映します。
TAggregatedObject は、そのコントローラーへの QueryInterface 呼び出しを単純に反映します。このような集約されたオブジェクトから、コントローラーがサポートする任意のインターフェイスを取得でき、コントローラーがサポートするインターフェイスのみを取得できます。これは、1 つ以上の内部オブジェクトを使用してコントローラー クラスで宣言されたインターフェイスを実装するコントローラー クラスを実装する場合に役立ちます。集約により、オブジェクト階層全体で実装の共有が促進されます。
TAggregatedObject は、特に "implements" 構文と組み合わせて使用する場合に、ほとんどの集約オブジェクトが継承する必要があるオブジェクトです。