В Delphi «интерфейс» имеет два различных значения. На жаргоне ООП вы можете думать об интерфейсе как о классе без реализации. В Delphi раздел интерфейса определения модуля используется для объявления любых общедоступных разделов кода, которые появляются в модуле. В этой статье интерфейсы будут объяснены с точки зрения ООП.
Если вы готовы создать надежное приложение таким образом, чтобы ваш код можно было поддерживать, повторно использовать, а гибкость ООП в Delphi поможет вам проехать первые 70% вашего маршрута. Определение интерфейсов и их реализация помогут с оставшимися 30%.
Абстрактные классы
Вы можете рассматривать интерфейс как абстрактный класс с удаленной реализацией и удалением всего, что не является общедоступным. Абстрактный класс в Delphi – это класс, который не может быть создан – вы не можете создать объект из класса, помеченного как абстрактный.
Давайте взглянем на пример объявление интерфейса:
type
IConfigChanged = interface [‘ {0D57624C-CDDE-458B-A36C-436AE465B477} ‘]
процедура ApplyConfigChange;
end ;
IConfigChanged – это интерфейс. Интерфейс определяется так же, как и класс, вместо слова «класс» используется ключевое слово «интерфейс». Значение Guid, следующее за ключевым словом interface, используется компилятором для уникальной идентификации интерфейса. Чтобы сгенерировать новое значение GUID, просто нажмите Ctrl + Shift + G в Delphi IDE. Каждый определяемый вами интерфейс требует уникального значения Guid.
Интерфейс в ООП определяет абстракцию – шаблон для фактического класса, который будет реализовывать интерфейс, – который будет реализовать методы, определенные интерфейсом. Интерфейс на самом деле ничего не делает, он имеет только сигнатуру для взаимодействия с другими (реализующими) классами или интерфейсами.
Реализация методов (функций, процедуры и свойства Get/Set методы) выполняется в классе, реализующем интерфейс. В определении интерфейса нет разделов области видимости (частных, общедоступных, опубликованных и т. Д.), Все является общедоступным. Тип интерфейса может определять функции, процедуры (которые в конечном итоге станут методами класса, реализующего интерфейс) и свойства. Когда интерфейс определяет свойство, он должен определять методы получения/установки – интерфейсы не могут определять переменные.
Как и в случае с классами, интерфейс может наследовать от других интерфейсов.
тип
IConfigChangedMore = интерфейс (IConfigChanged)
процедура ApplyMoreChanges;
end ;
Программирование
Большинство разработчиков Delphi, когда думают об интерфейсах, они думают о программировании COM.. Однако интерфейсы – это всего лишь функция ООП языка, они не привязаны конкретно к COM. Интерфейсы могут быть определены и реализованы в приложении Delphi, вообще не касаясь COM.
Реализация
Для реализации интерфейса вам потребуется чтобы добавить имя интерфейса в оператор класса, например:
type
TMainForm = класс (TForm, IConfigChanged)
public
процедура ApplyConfigChange;
end ;
В приведенном выше коде форма Delphi с именем «MainForm» реализует интерфейс IConfigChanged.
Предупреждение : когда класс реализует интерфейс, он должен реализовать все свои методы и свойства. Если вы не смогли/забыли реализовать метод (например: ApplyConfigChange), произойдет ошибка времени компиляции «Необъявленный идентификатор E2003: ‘ApplyConfigChange’» .
Предупреждение : если вы попытаетесь указать интерфейс без значения GUID, вы получите: «Тип E2086 ‘IConfigChanged’ еще не полностью определен» .
Пример
Рассмотрим приложение MDI, в котором пользователю могут одновременно отображаться несколько форм. Когда пользователь изменяет конфигурацию приложения, большинству форм необходимо обновить свое отображение – показать/скрыть некоторые кнопки, обновить заголовки меток и т. Д. Вам понадобится простой способ уведомить все открытые формы о том, что произошло изменение в конфигурации приложения. Идеальным инструментом для работы был интерфейс.
Каждая форма, которую необходимо обновить при изменении конфигурации, будет реализовывать IConfigChanged. Поскольку экран конфигурации отображается модально, следующий код при закрытии обеспечивает уведомление всех форм реализации IConfigChanged и вызов ApplyConfigChange:
процедура DoConfigChange ();
var
cnt: integer;
icc: IConfigChanged;
begin
для cnt: = 0 до -1 + Screen.FormCount do
begin
если поддерживает (Screen.Forms [cnt], IConfigChanged, icc) тогда
icc.ApplyConfigChange;
end ;
end ;
Функция Supports (определенная в Sysutils.pas) указывает, поддерживает ли данный объект или интерфейс указанный интерфейс. Код выполняет итерацию по коллекции Screen.Forms (объекта TScreen) – по всем формам, которые в данный момент отображаются в приложении. Если форма Screen.Forms [cnt] поддерживает интерфейс, Supports возвращает интерфейс для последнего параметра параметра и возвращает true.
Следовательно, если форма реализует IConfigChanged, переменную icc можно использовать для вызова методов интерфейса, реализованных формой. Обратите внимание, конечно, что каждая форма может иметь свою собственную реализацию процедуры ApplyConfigChange .
Предки
Любой класс, который вы определяете в Delphi, должен иметь предка. TObject является предком всех объектов и компонентов. Вышеупомянутая идея применима также к интерфейсам, IInterface является базовым классом для всех интерфейсов. IInterface определяет 3 метода: QueryInterface, _AddRef и _Release.
Это означает, что наш IConfigChanged также имеет эти 3 метода, но мы их не реализовали. Это потому, что TForm наследуется от TComponent, который уже реализует для вас IInterface! Если вы хотите реализовать интерфейс в классе, который наследуется от TObject, убедитесь, что ваш класс наследуется от TInterfacedObject. Поскольку TInterfacedObject – это TObject, реализующий IInterface. Например:
TMyClass = class ( TInterfacedObject , IConfigChanged)
процедура ApplyConfigChange;
end ;
В заключение , IUnknown = IInterface. IUnknown предназначен для COM.