Определяя абстрактный класс, являющийся базовым классом иерархии можно обнаружить, что разрабатываемый класс является настолько абстрактным что в его состав входят лишь виртуальные функции, не одна из которых не реализована в рамках этого класса. Т.е. класс содержит лишь объявления функций и не содержит не одного определения функций.
Такой, что абстрактный класс можно определить с использованием ключевого слова 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. Он уменьшает счетчик ссылок и проверяет не равен ли он нулю, и если необходимо уничтожает объект.
|
|
|
Отсутствует необходимость удалять объект самостоятельно.
Замечание: если мы работаем с объектами, основанными на интерфейсах, рекомендуется, чтобы доступ к таким объектам осуществлялся либо только при помощи переменных, ссылающихся на обычные объекты, либо только при помощи переменных интерфейсного типа. Смешивая подходы можно разрушить механизм подсчета ссылок.
механизм подсчета ссылок






