7.4 Делегация Интерфейса

На верх  Назад  Вперёд

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

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

Если класс имеет указатель на желаемый интерфейс, нужно указать компилятору что, когда запрашивается интерфейс IMyInterface, следует использовать ссылку на поле:

type
IMyInterface = interface
  procedure P1;
end;
 
TMyClass = class(TInterfacedObject, IMyInterface)
private
  FMyInterface: IMyInterface; // тип интерфейс
public
  property MyInterface: IMyInterface
      read FMyInterface implements IMyInterface;
end;

Интерфейс не должен обязательно быть полем, может быть использован любой способ чтения.

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

{$interfaces corba}
type
IMyInterface = interface
  procedure P1;
end;
 
// NOTE: Interface must be specified here  Примечание: Интерфейс должен быть указан здесь
TDelegateClass = class(TObject, IMyInterface)
private
  procedure P1;
end;
 
TMyClass = class(TInterfacedObject, IMyInterface)
private
  FMyInterface: TDelegateClass; // тип класса
  property MyInterface: TDelegateClass
    read FMyInterface implements IMyInterface;
end;

Следует отметить, что в отличии от Delphi, класс-делегат должен явно указать на интерфейс: компилятор не будет искать методы в классе делегате, он будет просто проверить, что класс-делегат реализует указанный интерфейс.

Нельзя смешивать отождествленные методы и делегирование интерфейса. Это значит, что нельзя реализовать часть интерфейса отождествлёнными методами, а часть через делегирование. В следующем примере сделана попытка реализовать IMyInterface частично отождествлёнными методами (P1), а частично через делегирование. Компилятор не примет код:

{$interfaces corba}
type
IMyInterface = interface
  procedure P1;
  procedure P2;
end;
 
TMyClass = class(TInterfacedObject, IMyInterface)
  FI : IMyInterface;
protected
  procedure IMyInterface.P1 = MyP1;
  procedure MyP1;
  property MyInterface: IMyInterface read FI implements IMyInterface;
end;

Компилятор выдаст ошибку:

Error: Interface "IMyInterface" can’t be delegated by "TMyClass", it already has method resolutions

Ошибка: Интерфейс "IMyInterface" не может быть делегирована "TMyClass", он уже имеет отождествлённый метод

Однако, можно реализовать один интерфейс посредством отождествлённых методов, а другой посредством делегирования:

{$interfaces corba}
type
IMyInterface = interface
  procedure P1;
end;
 
IMyInterface2 = interface
  procedure P2;
end;
 
TMyClass = class(TInterfacedObject,
                  IMyInterface, IMyInterface2)
  FI2 : IMyInterface2;
protected
  procedure IMyInterface.P1 = MyP1;
  procedure MyP1;
public
  property MyInterface: IMyInterface2
      read FI2 implements IMyInterface2;
end;