Подтвердить что ты не робот

Интерфейс 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, тогда выполняется деструктор.

4b9b3361

Ответ 1

Здесь происходит то, что вы вызываете TContainer.Create и создаете экземпляр для объекта. Но вы присваиваете этому экземпляру ссылку на интерфейс, глобальную переменную Foo. Поскольку эта переменная имеет тип IFoo, делегирование интерфейса означает, что объект-реализация является экземпляром TFooImpl и not экземпляра 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 предоставляет функциональные возможности для внутреннего объекта совокупность путем внедрения методов IIterterface для делегирования управляющий IInterface.

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

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

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

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

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

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

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

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

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