Delphi接口实现

Gry*_*ffe 13 delphi interface delphi-2007 implements

我希望引用计数应该在接口实现中的外部聚合对象上工作.如果我可以参考另一个例子:实现多个接口的类中的清晰度(替代委托):

这是行为的最小再现:

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.
Run Code Online (Sandbox Code Playgroud)

如果不是使用implements,我在TImplementor类中实现接口,然后运行析构函数.

Dav*_*nan 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.
Run Code Online (Sandbox Code Playgroud)

文档不谈论这个:

用于实现委托接口的类应该派生自TAggregationObject.

最初我找不到任何相关的文档TAggregationObject.最后我意识到它实际上已经命名TAggregatedObject并且有记录.

TAggregatedObject通过实现委托给控制IInterface的IInterface方法为聚合的内部对象提供功能.

聚合对象是由多个接口对象组成的对象.每个对象都实现自己的行为和接口,但所有对象共享相同的引用计数,即控制器对象的引用计数.在容器模式中,控制器是容器对象.

TAggregatedObject本身不支持任何接口.但是,正如聚合的典型情况一样,它确实实现了IInterface的方法,这些方法由从它下降的对象使用.因此,TAggregatedObject充当实现用于创建作为聚合的一部分的对象的接口的类的基础.

TAggregatedObject用作创建包含对象和连接对象的类的基础.使用TAggregatedObject可确保对IInterface方法的调用委托给聚合的控制IInterface.

控制IInterface在TAggregatedObject的构造函数中指定,并由Controller属性指示.

另外还有来自源代码的评论:

TAggregatedObject和TContainedObject是用于聚合或包含在外部控制对象中的接口对象的合适基类.在外部对象类声明中的接口属性上使用"implements"语法时,请使用这些类型来实现内部对象.

由聚合对象代表控制器实现的接口不应与控制器提供的其他接口区分开.聚合对象不得维护自己的引用计数 - 它们必须与其控制器具有相同的生命周期.为此,聚合对象将引用计数方法反映到控制器.

TAggregatedObject只是将QueryInterface调用反映到其控制器.从这样的聚合对象,可以获得控制器支持的任何接口,并且只能获得控制器支持的接口.这对于实现使用一个或多个内部对象来实现在控制器类上声明的接口的控制器类非常有用.聚合促进跨对象层次结构的实现共享.

TAggregatedObject是大多数聚合对象应该继承的内容,尤其是在与"implements"语法结合使用时.