Главная » Delphi » Интерфейсы Delphi

0

Возможно, наиболее важным  дополнением к языку Object Pascal стала поддержка интерфейсов (interfaces), введенная в Delphi 3. Интерфейс определяет набор  функций и процедур, которые могут быть  использованы для взаимодействия программы с объек том. Определение конкретного интерфейса известно и разработчику, и его пользовате лю и воспринимается как соглашение о правилах объявления и использования этого интерфейса. В классе  может  быть  реализовано несколько интерфейсов. В результате объект становится “многоликим”, являя клиенту каждого интерфейса свое особое лицо.

Интерфейсы представляют собой  только  определения того,  каким  образом могут сообщаться между собой  объект и его клиент. Данная концепция схожа с концепцией чистых виртуальных классов  (PURE VIRTUAL) языка  C++. Класс,  обеспечивающий поддержку  некоторого интерфейса, обязан обеспечить и реализацию всех  его функ ций и процедур.

В настоящей главе речь  пойдет лишь о синтаксических элементах интерфейсов. Бо лее подробная информация по этой теме приведена в главе 15, “Разработка приложений COM”.

Определение интерфейса

Подобно тому, как все классы  языка  Object Pascal происходят от класса  TObject, все интерфейсы явно  или неявно являются потомками интерфейса IUnknown, опре деление которого в модуле System выглядит следующим образом:

type

IUnknown = interface

[‘{00000000-0000-0000-C000-000000000046}’]

function QueryInterface(const IID: TGUID; out Obj): Integer;

stdcall;

function _AddRef: Integer; stdcall;

function _Release: Integer; stdcall;

end;

Как видите, синтаксис определения интерфейса очень  похож  на синтаксис опреде ления  класса. Основное различие между ними  заключается в том, что интерфейс, в от личие от класса,  может  быть  связан  с глобальным уникальным идентификатором (Globally Unique Identifier —  GUID).  Определение интерфейса IUnknown “происходит” из  спе цификации модели компонентных  объектов  (COM —  Component Object  Model) Microsoft. Более подробная информация по этой  теме  приведена в главе  15, “Разработка прило жений COM”.

Для  того,  кто  умеет  создавать классы,  определение собственного интерфейса  в Delphi не представляет особых  сложностей. Ниже  приведен пример определения но вого интерфейса IFoo, который реализует единственный метод F1().

type

IFoo = interface

[‘{2137BF60-AA33-11D0-A9BF-9A4537A42701}’]

function F1: Integer;

end;CОВЕТ

Интегрированная среда разработки Delphi создает новый GUID при нажатии комбина-

ции клавиш <Ctrl+Shift+G>.

Следующий код определяет новый  интерфейс IBar, производный от IFoo:type

IBar = interface(IFoo)

[‘{2137BF61-AA33-11D0-A9BF-9A4537A42701}’]

function F2: Integer;

end;

Реализация интерфейса

Приведенный ниже  фрагмент кода демонстрирует реализацию интерфейсов IFoo

и IBar в классе TFooBar.

type

TFooBar = class(TInterfacedObject, IFoo, IBar)

function F1: Integer;

function F2: Integer;

end;

function TFooBar.F1: Integer;

begin

Result := 0;

end;

function TFooBar.F2: Integer;

begin

Result := 0;

end;

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

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

type

IFoo = interface

[‘{2137BF60-AA33-11D0-A9BF-9A4537A42701}’]

function F1: Integer;

end;

IBar = interface

[‘{2137BF61-AA33-11D0-A9BF-9A4537A42701}’]

function F1: Integer;

end;

TFooBar = class(TInterfacedObject, IFoo, IBar)

// Назначение методам псевдонимов

function IFoo.F1 = FooF1;

function IBar.F1 = BarF1;// Методы интерфейса function FooF1: Integer; function BarF1: Integer;

end;

function TFooBar.FooF1: Integer;

begin

Result := 0;

end;

function TFooBar.BarF1: Integer;

begin

Result := 0;

end;

Директива implements

Директива implements впервые была  введена  в Delphi  4. Она  позволяет делеги ровать реализацию методов интерфейса другим классам или интерфейсам. Она всегда указывается как последняя директива в объявлении свойства класса или интерфейса:

type

TSomeClass = class(TInterfacedObject, IFoo)

// …

function GetFoo: TFoo;

property Foo: TFoo read GetFoo implements IFoo;

// …

end;

В приведенном примере использование директивы implements говорит о  том, что методы, реализующие интерфейс IFoo, следует искать  в свойстве Foo. Тип свой ства  должен  быть  классом,  содержащим методы  IFoo, интерфейс IFoo или  его  по томков.  В директиве implements можно  использовать не один,  а целый  список  ин терфейсов (элементы списка  должны  отделяться запятыми). В таком  случае класс, ис пользуемый для представления свойства, должен  содержать методы, реализующие все приведенные в списке интерфейсы.

Директива implements позволяет выполнять бесконфликтную агрегацию. Агрегация (aggregation) —  это  концепция COM,  отвечающая за комбинацию нескольких классов для выполнения одной задачи.  (Более подробная информация по данной теме приведе на в главе 15, “Разработка приложений COM”.) Другое немаловажное достоинство при менения директивы implements заключается в том,  что  она  позволяет отложить ис пользование необходимых для реализации интерфейса ресурсов до того момента, когда они потребуются реально. Предположим, что в реализации некоторого интерфейса не обходим  мегабайт памяти для хранения растрового изображения, но этот  интерфейс применяется достаточно редко.  Вряд ли можно  считать эффективным решение посто янно выделять мегабайт памяти, который будет использоваться лишь время  от времени. Директива implements позволяет реализовать интерфейс в отдельном классе,  экземп ляр которого будет создаваться только по прямому запросу пользователя.

Использование интерфейсов

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

var

I: ISomeInterface;

begin

// I инициализируется значением nil

I := FunctionReturningAnInterface;     // Счетчик ссылок

// увеличивается на 1

I.SomeFunc;        // Счетчик ссылок уменьшается на 1.

// Когда значение счетчика станет равным 0,

// объект I будет автоматически уничтожен.

end;

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

procedure Test(FB: TFooBar)

var

F: IFoo;

begin

F := FB;     // Корректно, поскольку FB поддерживает IFoo

.

.

.

Последнее правило гласит, что  для переменной типа  интерфейса может  быть  ис пользован оператор преобразования типов  as как  вызов  метода  QueryInterface, возвращающего адрес  другой  переменной типа  интерфейса (не  отчаивайтесь, если это  правило пока  не  до конца  понятно, —  более  подробная информация по  данной теме приведена в главе 15, “Разработка приложений COM”). Указанное правило мож но проиллюстрировать следующим примером:

var

FB: TFooBar;

F: IFoo;

B: IBar;

begin

FB := TFooBar.Create

F := FB;       // Допустимо, так как FB поддерживает IFoo

B := F as IBar;       // Вызов функции QueryInterface F для IBar

.

.

.

Если запрошенный  интерфейс  не  поддерживается,  то  будет  передано  соответст

вующее исключение.

Источник: Тейксейра, Стив, Пачеко, Ксавье.   Borland Delphi 6. Руководство разработчика. : Пер.  с англ. — М. : Издательский дом “Вильямс”, 2002. —  1120 с. : ил. — Парал. тит. англ.

По теме:

  • Комментарии