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

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

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

С формальной точки зрения интерфейс не является классом, хотя может быть похожим на него. Интерфейсы рассматриваются как отдельный элемент …..,обладающий след. особенностями:

1) при работе с объектами интерфейсного типа осуществляется автоматический подсчет ссылок на эти объекты.

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

2) класс потомок может обладать единственным классом предком, но при этом он может обладать несколькими интерфейсами (реализовывать несколько интерфейсов).

3)Все классы являются потомками класса Tobject’a. Все интерфейсы являются потомками IInterface, при этом формируется современно отдельная иерархия.

До 6 версии Дельфи был IUnnoun. Потом ввели IInterface, для того чтобы подчеркнуть разницу между Microsoft COM и IInterface.

Com – Component Object Library – это технология, определяющая стандартный способ взаимодействия модулей клиента и сервера через специальный интерфейс. Здесь “модуль” обозначает приложение или библиотеку dll, два модуля могут выполняться на одном и том же компьютере или на разных компьютерах локальной сети. Существует множество различных интерфейсов в зависимости от задач, выполняемых клиентом и сервером.

Интерфейсы реализуются на объектах серверах. COM сервер обычно реализует более одного интерфейса. Все серверы обладают рядом object возможностей, т.к. все они должны реализовать интерфейс Iunnoun. Этот интерфейс продублирован в виде IInterface для работы с интрефейсами без COM, это базовый интерфейс, от него наследуется любой интерфейс в Дельфи, в дельфи существует несколько различных классов с готовой реализацией интерфейсов Iunnoun. IInterface, среди которых IInterfacedObject (!) и TComObject.

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

Интерфейсы как классы могут быть только объявлены глобально в программе или модуле.

Type

Имя интер-са = interface (предок)

[‘{GUID}’]

Список членов

End;

GUID – глобальный …идентификатор. Уникальный цифровой идентификатор, формируемый в соответствии с определенными правилами, и назначаемый каждому из зарегистрированных интерфейсов. Чтобы его сгенерировать достаточно нажать комбинацию клавиш ctr+shift+ G.

Type ICanFly = interface

[‘{ }’]

Function Fly: string;

End;

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

TAirPlane = class(TInterfacedObject, ICanFly) // чтобы наш класс имел все из //IInterface…

Function Fly:string; virtual;

В дельфи имеется несколько базовых классов, реализующих базовое поведение интерфейса IInterface. Самый простой из них – TInterfacedObject.

Методы, входящие в состав интерфейса нужно реализовать либо как статические, либо как виртуальные, виртуальные можно переопределить в дочерних классах с помощью директивы override.

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

Оба подхода использования статических и виртуальных методов одинаково удобные и гибкие, однако, все – таки лучше использовать статические методы. Это связано с особенностями реализации вызова функции интерфейса. Чтобы настроить точки входа интерфейсных функций компилятор вставляет в исполняемый код подпрограммы-заглушки, каждая из которых обеспечивает коррекцию указателя self, и передачу управления соответствующего класса, реализующего интерфейс. Заглушка для статического метода обладает простой структурой, а для виртуального метода устроена сложнее и занимает гораздо больше памяти (до 30 байт) + еще увеличивается таблица VMT этого класса и дочерних классов.

Вывод: Поэтому использование статических методов делает код меньшим по размеру при той же степени полиморфизма

После того как класс TAirPlane будет реализован, приведем пример кода, который будет его использовать.

1 Вариант

var Airplane1:TAirplane;

Begin

Airplane1:=TAirplane.Create;

Airplane1.Fly;

Airplane1.Free;

End;

2 Вариант

Var Flyer1:TCanFly;

Begin

Flyer1:=TAirplane.Create;

Flyer1.Fly;

End;

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

Flyer1:=Tairplane.Create as ICanFly;

//если класс реализует больше 2 интерфейсов.

Операция as для интерфейсов отличается от операции as для классов

Исполняемый код, генерируемый компилятором для операции as при использовании этой операции совместно с интерфейсами отличается от кода, который генерируется компилятором в случае, если операция as используется в отношении класса.

В отношении классов в исполняемый код добавляется осуществляемая в процессе исполнения программы проверка того, что объект принадлежит классу, совместимому с данным.

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

В обоих случаях, и при явном присваивании, и при использовании операции as, выполняется одна дополнительная операция: происходит обращение к методу _AddRef, определенному в рамках IInterface и реализованному в TInterfacedObject. В рез – е увеличивается счетчик ссылок этого объекта. Как только переменная Flyer1 выйдет из области видимости, вызывается метод _Release, который тоже является частью IInterface и тоже реализован в TInterfacedObject. Он уменьшает счетчик ссылок и проверяет не равен ли он нулю, и если необходимо уничтожает объект.

Отсутствует необходимость удалять объект самостоятельно.

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

механизм подсчета ссылок


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: