Интерфейс Delphi реализует

Я ожидал бы, что подсчет ссылок должен работать на внешнем объекте агрегирования в реализации интерфейса. Если я могу сослаться на другой пример:ясность в классах, реализующих несколько интерфейсов (альтернатива делегированию):

вот минимальное воспроизведение поведения:

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 класс затем запускается деструктор.

1 ответов


здесь происходит то, что вы называете 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 предоставляет функциональные возможности для внутреннего объекта aggregate путем реализации методов IInterface для делегирования контроль IInterface.

агрегированный объект-это объект, состоящий из несколько сопряженных объекты. Каждый объект реализует свое собственное поведение и интерфейсы, но все объекты имеют один и тот же счетчик ссылок, который является объект контроллера. В шаблоне контейнера контроллер является объект контейнера.

TAggregatedObject сам по себе не поддерживает интерфейсы. Однако, как является типичным для aggregate, он реализует методы IInterface, которые используются объектами, которые спускаются с него. TAggregatedObject, поэтому служит основой для классов, которые реализовать интерфейсы для создания объектов, являющихся частью объединять.

TAggregatedObject используется в качестве базы для классов, которые создают содержащиеся объекты и соединяющие объекты. Использование TAggregatedObject гарантирует, что вызовы делегата методов IInterface управляющему IInterface из совокупности.

управляющий IInterface указан в конструкторе для TAggregatedObject и указывается свойством Controller.

кроме того, есть это из комментариев исходного кода:

TAggregatedObject и TContainedObject являются подходящими базовыми классами для сопряженных объектов, предназначенных для агрегирования или содержащихся в внешний объект управления. При использовании синтаксиса "implements" на свойство interface в объявлении класса внешнего объекта используйте следующие типы для реализации внутреннего объекта.

интерфейсы, реализованные агрегированными объектами от имени контроллер не должен отличаться от других интерфейсов обеспечивается контроллером. Агрегированные объекты не должны поддерживаться их собственный подсчет ссылок - они должны иметь такую же продолжительность жизни, как их контролер. Для этого агрегированные объекты отражают методы подсчета ссылок на контроллер.

TAggregatedObject просто отражает вызовы QueryInterface его контроллер. Из такого агрегированного объекта можно получить любой интерфейс, который поддерживает контроллер, и только интерфейсы, которые поддержка контроллера. Это полезно для реализации контроллера класс, использующий один или несколько внутренних объектов для реализации интерфейсы, объявленные в классе контроллера. Агрегация способствует совместное использование реализации в иерархии объектов.

TAggregatedObject-это то, что должно наследовать большинство агрегатных объектов от, особенно при использовании совместно с " implements" синтаксис.