我希望引用计数应该适用于接口实现中的外部聚合对象。 如果我可以参考另一个例子:Clarity in classes implementing multiple interfaces (alternative to delegation):
这是行为的最小再现:
program SO16210993;
{$APPTYPE CONSOLE}
type
IFoo = interface
procedure Foo;
end;
TFooImpl = class(TInterfacedObject, IFoo)
procedure Foo;
end;
TContainer = class(TInterfacedObject, IFoo)
private
FFoo: IFoo;
public
constructor Create;
destructor Destroy; override;
property Foo: IFoo read FFoo implements IFoo;
end;
procedure TFooImpl.Foo;
begin
Writeln('TFooImpl.Foo called');
end;
constructor TContainer.Create;
begin
inherited;
FFoo := TFooImpl.Create;
end;
destructor TContainer.Destroy;
begin
Writeln('TContainer.Destroy called');//this line never runs
inherited;
end;
procedure Main;
var
Foo : IFoo;
begin
Foo := TContainer.Create;
Foo.Foo;
end;
begin
Main;
Readln;
end.
如果不是使用implements
,而是在TImplementor
类中实现接口,那么析构函数就会运行。
答案 0 :(得分:15)
这里发生的是您调用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.
documentation确实谈到了这个:
用于实现委托接口的类应该派生自TAggregationObject。
最初我找不到此TAggregationObject
的任何文档。最后我意识到它实际上被命名为TAggregatedObject
并且是documented。
TAggregatedObject为一个内部对象提供了功能 通过实施IInterface方法聚合到 控制IInterface。
聚合对象是由多个接口组成的对象 对象。每个对象都实现自己的行为和接口,但是 所有对象共享相同的引用计数,即 控制器对象。在容器模式中,控制器是 容器对象。
TAggregatedObject本身不支持任何接口。但是,作为 是典型的聚合,它确实实现了方法 IInterface,由从它下降的对象使用。 因此,TAggregatedObject充当类的基础 实现用于创建属于的对象的接口 聚合
TAggregatedObject用作创建包含的类的基础 对象和连接对象。使用TAggregatedObject确保 调用IInterface方法委托给控制IInterface 总计。
控制IInterface在构造函数中指定 TAggregatedObject并由Controller属性指示。
此外还有来自源代码的评论:
TAggregatedObject和TContainedObject是合适的基类 对于要聚合或包含在的接口对象 外部控制对象。在上使用“implements”语法时 外部对象类声明中的interface属性,使用这些 实现内部对象的类型。
由聚合对象代表的接口实现的 控制器不应与其他接口区分开来 由控制器提供。不得维护聚合对象 他们自己的引用计数 - 它们必须具有相同的生命周期 他们的控制器为实现这一目标,聚合对象反映了这一点 控制器的引用计数方法。
TAggregatedObject只是反映了对其的QueryInterface调用 控制器。从这样的聚合对象,可以获得任何 控制器支持的接口,只有接口 控制器支持。这对于实现控制器很有用 使用一个或多个内部对象来实现的类 在控制器类上声明的接口。聚合促进 跨对象层次结构实现共享。
TAggregatedObject是大多数聚合对象应该继承的东西 来自,特别是与“工具”一起使用时 语法。