- •Динамически загружаемые библиотеки
- •5.1. Динамически загружаемые библиотеки
- •5.2. Разработка библиотеки
- •5.2.1. Структура библиотеки
- •5.2.2. Экспорт подпрограмм
- •5.2.3. Соглашения о вызове подпрограмм
- •5.3. Использование библиотеки в программе
- •5.3.1. Статический импорт
- •5.3.2. Модуль импорта
- •5.3.3. Динамический импорт
- •5.3.4. Глобальные переменные и константы
- •5.3.5. Инициализация и завершение работы библиотеки
- •5.3.6. Исключительные ситуации и ошибки выполнения подпрограмм
- •5.3.7. Общий менеджер памяти
- •5.3.8. Стандартные системные переменные
- •Программирование на языке Delphi
- •6.1. Понятие интерфейса
- •6.2. Описание интерфейса
- •6.3. Расширение интерфейса
- •6.4. Глобально-уникальный идентификатор интерфейса
- •6.5. Реализация интерфейса
- •6.6. Использование интерфейса
- •6.7. Реализация нескольких интерфейсов
- •6.8. Реализация интерфейса несколькими классами
- •6.9. Связывание методов интерфейса с методами класса
- •6.10. Реализация интерфейса вложенным объектом
- •6.11. Совместимость интерфейсов
- •6.12. Совместимость класса и интерфейса
- •6.13. Получение интерфейса через другой интерфейс
- •6.14. Механизм подсчета ссылок
- •6.15. Представление интерфейса в памяти
- •6.16. Применение интерфейса для доступа к объекту dll-библиотеки
- •6.17. Итоги
- •7.1. Проект
- •7.1.1. Понятие проекта
- •7.1.2. Файлы описания форм
- •7.1.3. Файлы программных модулей
- •7.1.4. Главный файл проекта
- •7.1.5. Другие файлы проекта
- •7.2. Управление проектом
- •7.2.1. Создание, сохранение и открытие проекта
- •7.2.2. Окно управления проектом
- •7.2.3. Группы проектов
- •7.2.4. Настройка параметров проекта
- •7.2.5. Компиляция и сборка проекта
- •7.2.6. Запуск готового приложения
- •7.3. Форма
- •7.3.1. Понятие формы
- •7.3.2. Имя и заголовок формы
- •7.3.3. Стиль формы
- •7.3.4. Размеры и местоположение формы на экране
- •7.3.5. Цвет рабочей области формы
- •7.3.6. Рамка формы
- •7.3.7. Значок формы
- •7.3.8. Невидимая форма
- •7.3.9. Прозрачная форма
- •7.3.10. Полупрозрачная форма
- •7.3.11. Недоступная форма
- •7.3.12. События формы
- •7.4. Несколько форм в приложении
- •7.4.1. Добавление новой формы в проект
- •7.4.2. Добавление новой формы из Хранилища Объектов
- •7.4.3. Переключение между формами во время проектирования
- •7.4.4. Выбор главной формы приложения
- •7.4.5. Вызов формы из программы
- •7.5. Компоненты
- •7.5.1. Понятие компонента
- •7.5.2. Визуальные и невизуальные компоненты
- •7.5.3. «Оконные» и «графические» компоненты
- •7.5.4. Общие свойства визуальных компонентов
- •7.5.5. Общие события визуальных компонентов
- •7.6. Управление компонентами при проектировании
- •7.6.1. Помещение компонентов на форму и их удаление
- •7.6.2. Выделение компонентов на форме
- •7.6.3. Перемещение и изменение размеров компонента
- •7.6.4. Выравнивание компонентов на форме
- •7.6.5. Использование Буфера обмена
- •7.7. Закулисные объекты приложения
- •7.7.1. Application — главный объект, управляющий приложением
- •7.7.2. Screen — объект, управляющий экраном
- •7.7.3. Mouse — объект, представляющий мышь
- •7.7.4. Printer — объект, управляющий принтером
- •7.7.5. Clipboard — объект, управляющий Буфером обмена
- •7.8. Итоги
6.7. Реализация нескольких интерфейсов
Один класс может содержать реализацию нескольких интерфейсов. Такая возможность позволяет воплотить в классе несколько понятий. Например, класс TTextReader — "считыватель табличных данных" — может выступить еще в одной роли — "считыватель строк". Для этого он должен реализовать интерфейс IStringIterator:
|
type IStringIterator = interface function Next: string; function Finished: Boolean; end; |
Интерфейс IStringIterator предназначен для последовательного доступа к списку строк. Метод Next возвращает очередную строку из списка, метод Finished проверяет, достигнут ли конец списка.
Реализуем интерфейс IStringIterator в классе TTextReader таким образом, чтобы последовательно считывались значения из ячеек таблицы. Например, представьте, что в некотором файле дана таблица:
|
Aaa Bbb Ccc Ddd Eee Fff Ggg Hhh Iii |
Чтение этой таблицы через интерфейс IStringIterator вернет следующую последовательность строк:
|
Aaa Bbb Ccc Ddd Eee Fff Ggg Hhh Iii |
Ниже приведен программный код, обеспечивающий поддержку интерфейса IStringIterator в классе TTextReader:
|
type TTextReader = class(TInterfacedObject, ITextReader, IStringIterator) FColumnIndex: Integer; function Next: string; function Finished: Boolean; ... end; ...
function TTextReader.Next: string; begin if FColumnIndex = ItemCount then // Если пройден последний элемент текущей строки, begin // то переходим к следующей строке таблицы NextLine; FColumnIndex := 0; end; Result := Items[FColumnIndex]; FColumnIndex := FColumnIndex + 1; end;
function TTextReader.Finished: string; begin Result := EndOfFile and (FColumnIndex = ItemCount); end; |
Теперь объекты класса TTextReader совместимы сразу с тремя типами данных: TInterfacedObject, ITextReader, IStringIterator.
|
var Obj: TTextReader; Reader: ITextReader; Iterator: IStringIterator; begin ... Reader := Obj; // Правильно Iterator := Obj; // Правильно ... end; |
В одном случае объект класса TTextReader рассматривается как считыватель табличных данных, а в другом случае — как обычный список строк с последовательным доступом. Например, если есть две процедуры:
|
procedure LoadTable(Reader: ITextReader); procedure LoadStrings(Iterator: IStringIterator); |
то объект класса TTextReader можно передать в обе процедуры:
|
LoadTable(Obj); // Obj воспринимается как ITextReader LoadStrings(Obj); // Obj воспринимается как IStringIterator |
6.8. Реализация интерфейса несколькими классами
Несколько совершенно разных классов могут содержать реализацию одного и того же интерфейса. С объектами таких классов можно работать так, будто у них есть общий базовый класс. Интерфейс выступает аналогом общего базового класса.
Рассмотрим пример. Представьте, что есть два класса: TTextReader и TIteratableStringList:
|
type TTextReader = class(TInterfacedObject, ITextReader, IStringIterator) ... end;
TIteratableStringList = class(TStringList, IStringIterator) ... end; |
Схематично полученную иерархию классов можно представить так (рисунок 6.2):
Рисунок
6.2. Иерархия классов, реализующих
интерфейсы. Сплошными линиями отмечено
наследование классов, а пунктирными
линиями — реализация интерфейсов
классами.
Объекты классов TTextReader и TIteratableStringList несовместимы между собой. Тем не менее, они совместимы с переменными типа IStringIterator. Это значит, что если есть процедура:
|
procedure LoadStrings(Iterator: IStringIterator); |
то вы можете передавать ей объекты обоих упомянутых классов в качестве аргумента:
|
var ReaderObj: TTextReader; StringsObj: TIteratableStringList; begin ... LoadStrings(ReaderObj); // Все правильно LoadStrings(StringsObj); // Все правильно ... end; |
