- Любовные романы
- Фантастика и фэнтези
- Ненаучная фантастика
- Ироническое фэнтези
- Научная Фантастика
- Фэнтези
- Ужасы и Мистика
- Боевая фантастика
- Альтернативная история
- Космическая фантастика
- Попаданцы
- Юмористическая фантастика
- Героическая фантастика
- Детективная фантастика
- Социально-психологическая
- Боевое фэнтези
- Русское фэнтези
- Киберпанк
- Романтическая фантастика
- Городская фантастика
- Технофэнтези
- Мистика
- Разная фантастика
- Иностранное фэнтези
- Историческое фэнтези
- LitRPG
- Эпическая фантастика
- Зарубежная фантастика
- Городское фентези
- Космоопера
- Разное фэнтези
- Книги магов
- Любовное фэнтези
- Постапокалипсис
- Бизнес
- Историческая фантастика
- Социально-философская фантастика
- Сказочная фантастика
- Стимпанк
- Романтическое фэнтези
- Ироническая фантастика
- Детективы и Триллеры
- Проза
- Юмор
- Феерия
- Новелла
- Русская классическая проза
- Современная проза
- Повести
- Контркультура
- Русская современная проза
- Историческая проза
- Проза
- Классическая проза
- Советская классическая проза
- О войне
- Зарубежная современная проза
- Рассказы
- Зарубежная классика
- Очерки
- Антисоветская литература
- Магический реализм
- Разное
- Сентиментальная проза
- Афоризмы
- Эссе
- Эпистолярная проза
- Семейный роман/Семейная сага
- Поэзия, Драматургия
- Приключения
- Детская литература
- Загадки
- Книга-игра
- Детская проза
- Детские приключения
- Сказка
- Прочая детская литература
- Детская фантастика
- Детские стихи
- Детская образовательная литература
- Детские остросюжетные
- Учебная литература
- Зарубежные детские книги
- Детский фольклор
- Буквари
- Книги для подростков
- Школьные учебники
- Внеклассное чтение
- Книги для дошкольников
- Детская познавательная и развивающая литература
- Детские детективы
- Домоводство, Дом и семья
- Юмор
- Документальные книги
- Бизнес
- Работа с клиентами
- Тайм-менеджмент
- Кадровый менеджмент
- Экономика
- Менеджмент и кадры
- Управление, подбор персонала
- О бизнесе популярно
- Интернет-бизнес
- Личные финансы
- Делопроизводство, офис
- Маркетинг, PR, реклама
- Поиск работы
- Бизнес
- Банковское дело
- Малый бизнес
- Ценные бумаги и инвестиции
- Краткое содержание
- Бухучет и аудит
- Ораторское искусство / риторика
- Корпоративная культура, бизнес
- Финансы
- Государственное и муниципальное управление
- Менеджмент
- Зарубежная деловая литература
- Продажи
- Переговоры
- Личная эффективность
- Торговля
- Научные и научно-популярные книги
- Биофизика
- География
- Экология
- Биохимия
- Рефераты
- Культурология
- Техническая литература
- История
- Психология
- Медицина
- Прочая научная литература
- Юриспруденция
- Биология
- Политика
- Литературоведение
- Религиоведение
- Научпоп
- Психология, личное
- Математика
- Психотерапия
- Социология
- Воспитание детей, педагогика
- Языкознание
- Беременность, ожидание детей
- Транспорт, военная техника
- Детская психология
- Науки: разное
- Педагогика
- Зарубежная психология
- Иностранные языки
- Филология
- Радиотехника
- Деловая литература
- Физика
- Альтернативная медицина
- Химия
- Государство и право
- Обществознание
- Образовательная литература
- Учебники
- Зоология
- Архитектура
- Науки о космосе
- Ботаника
- Астрология
- Ветеринария
- История Европы
- География
- Зарубежная публицистика
- О животных
- Шпаргалки
- Разная литература
- Зарубежная литература о культуре и искусстве
- Пословицы, поговорки
- Боевые искусства
- Прочее
- Периодические издания
- Фанфик
- Военное
- Цитаты из афоризмов
- Гиды, путеводители
- Литература 19 века
- Зарубежная образовательная литература
- Военная история
- Кино
- Современная литература
- Военная техника, оружие
- Культура и искусство
- Музыка, музыканты
- Газеты и журналы
- Современная зарубежная литература
- Визуальные искусства
- Отраслевые издания
- Шахматы
- Недвижимость
- Великолепные истории
- Музыка, танцы
- Авто и ПДД
- Изобразительное искусство, фотография
- Истории из жизни
- Готические новеллы
- Начинающие авторы
- Спецслужбы
- Подростковая литература
- Зарубежная прикладная литература
- Религия и духовность
- Старинная литература
- Справочная литература
- Компьютеры и Интернет
- Блог
Основы объектно-ориентированного программирования - Бертран Мейер
Шрифт:
Интервал:
Закладка:
Этот случай отнюдь не является исключением. Вот еще два примера того же рода.
[x]. Предположим, вы проектируете класс, описывающий структуру данных с операцией sort, упорядочивающей элементы структуры в соответствии с некоторым критерием сортировки. Тогда элементы этой структуры должны принадлежать типу, для которого определена операция сравнения infix "<=", задающая порядок для любой пары соответствующих объектов.
[x]. При разработке таких базисных структур данных как словари зачастую используется для хранения данных хеш-таблица, в которой место элемента определяется ключом, вычисляемым по значению элемента. Элементы, размещаемые в словаре должны принадлежать классу, допускающему применение хеш-функции, вычисляющей ключ каждого элемента.
Не ОО-подход
Переходя к решению этой проблемы, посмотрим, как с такой задачей справлялись другие, не ОО-языки.
В языке Ada нет классов, но зато есть пакеты для группировки взаимосвязанных типов и операций. Пакет может быть родовым, с родовыми параметрами, представляющими типы. При этом возникает та же проблема: пакет VECTOR_PROCESSING может включать объявление типа VECTOR и эквивалент нашей функции infix "+".
Решение в языке Ada рассматривает необходимые операции, например инфиксное сложение, как родовые параметры. Параметрами пакета могут быть не только типы, как при объектном подходе, но и подпрограммы. Например:
generic
type G is private;
with function "+" (a, b: G) return G is <>;
with function "*" (a, b: G) return G is <>;
zero: G; unity: G;
package VECTOR_HANDLING is
... Интерфейс пакета ...
end VECTOR_HANDLING
Заметим, что наряду с типом G и подпрограммами родовым параметром служит значение zero - нулевой элемент сложения. Типичное использования пакета:
package BOOLEAN_VECTOR_HANDLING is
new VECTOR_HANDLING (BOOLEAN, "or", "and", false, true);
В этом примере логическая операция or используется как сложение, and - умножение, а также задаются соответствующие значения для zero и unity. Подробнее мы обсудим этот пример в одной из следующих лекций курса.
Являясь решением для Ada, данный прием не применим в объектной среде. Основа ОО-подхода - приоритет типов данных над операциями при декомпозиции ПО, чьим следствием является отсутствие независимых операций. Всякая операция принадлежит некоторому типу данных, основанному на классе. Следовательно, возникшая "на пустом месте" функция, скажем, infix "+", не может быть фактическим родовым параметром, стоящим в одном ряду с типами INTEGER и BOOLEAN. То же касается и значений, таких как zero и unity, обязанных знать свое место - быть компонентами класса - вполне респектабельными членами ОО-сообщества.
Ограничение родового параметра
Эти наблюдения дают решение. Мы должны оперировать исключительно терминами классов и типов.
Потребуем, чтобы любой фактический параметр, используемый классом VECTOR (в других примерах по аналогии), был типом, поставляемым с множеством операций: infix "+", zero для инициализации суммы и т.д. Владея наследованием, мы знаем, как снабдить тип нужными операциями, - нужно просто сделать его потомком класса, отложенного или эффективного, обладающего этими операциями.
Синтаксически это выглядит так:
class C [G -> CONSTRAINING_TYPE] ... Все остальное как обычно ...
где CONSTRAINING_TYPE - произвольный тип, именуемый родовым ограничением (generic constraint). Символ -> обозначает стрелку на диаграммах наследования. Результат этого объявления в том, что:
[x]. в роли фактических родовых параметров могут выступать лишь типы, совместимые с CONSTRAINING_TYPE;
[x]. в классе C над сущностью типа G допускаются только те операции, которые допускаются над сущностью CONSTRAINING_TYPE, другими словами, представляющими собой компоненты базового класса этого типа.
Какое родовое ограничение использовать для класса VECTOR? Обсуждая множественное наследование, мы ввели в рассмотрение NUMERIC - класс объектов, допускающих базисные арифметические операции: сложение и умножение с нулем и единицей (лежащая в его основе математическая структура называется кольцом). Эта модель кажется вполне уместной, хотя нам необходимо пока только сложение. Соответственно, класс будет описан так:
indexing
description: "Векторы, допускающие сложение"
class
VECTOR [G -> NUMERIC]
... Остальное - как и раньше (но теперь правильно!) ...
После чего ранее некорректная конструкция в теле цикла
Result.put(item (i) + other.item (i), i)
становится допустимой, поскольку item (i) и other.item (i) имеют тип G, а значит, к ним применимы все операции NUMERIC, включая, инфиксный "+".
Следующие родовые порождения корректны, если полагать, что все классы, представленные как фактические родовые параметры, являются потомками NUMERIC:
VECTOR [NUMERIC]
VECTOR [REAL]
VECTOR [COMPLEX]
Класс EMPLOYEE не порожден от NUMERIC, так что попытка использовать VECTOR [EMPLOYEE] приведет к ошибке времени компиляции.
Абстрактный характер NUMERIC не вызывает никаких проблем. Фактический параметр при порождении может быть как эффективным (примеры выше), так и отложенным (VECTOR [NUMERIC_COMPARABLE]), если он порожден от NUMERIC.
Аналогично описываются класс словаря и класс, поддерживающий сортировку:
class DICTIONARY [G, H -> HASHABLE] ...
class SORTABLE [G -> COMPARABLE] ...
Игра в рекурсию
Вот некий трюк с нашим примером: спросим себя, возможен ли вектор векторов? Допустим ли тип VECTOR [VECTOR [INTEGER]]?
Ответ следует из предыдущих правил: только если фактический родовой параметр совместим с NUMERIC. Сделать это просто - породить класс VECTOR от класса NUMERIC (см. упражнение 16.2):
indexing
description: "Векторы, допускающие сложение"
class
VECTOR [G -> NUMERIC]
inherit
NUMERIC
... Остальное - как и раньше...
Векторы, подобные этому, можно и впрямь считать "числовыми". Операции сложение и умножение дают структуру кольца, в котором роль нуля (zero) играет вектор из G-нулей, и роль единицы (unity) - вектор из G-единиц. Операция сложения в этом кольце - это, строго говоря, векторный вариант infix "+", речь о котором шла выше.
Можно пойти дальше и использовать VECTOR [VECTOR [VECTOR [INTEGER]]] и так далее - приятное рекурсивное приложение ограниченной универсальности.
И снова неограниченная универсальность
Конечно же, не все случаи универсальности ограничены. Форма - STACK [G] или ARRAY [G] - по-прежнему существует и называется неограниченной универсальностью. Пример DICTIONARY [G, H -> HASHABLE] показывает, что класс одновременно может иметь как ограниченные, так и неограниченные родовые параметры.
Изучение ограниченной универсальности дает шанс лучше понять неограниченный случай. Вы, конечно же, вывели правило, по которому class C [G] следует понимать как class C [G -> ANY]. Поэтому если G - неограниченный типовой параметр (например, класса STACK), а x - сущность, имеющая тип G, то мы точно знаем, что можем делать с сущностью x: читать и присваивать значения, сравнивать (=, /=), передавать как параметр и применять в универсальных операциях clone, equal и прочее.
Попытка присваивания
Наша следующая техника адресуется к тем областям Объектной страны, в которых из страха тиранического поведения мы не можем позволить править простым правилам типизации, не встречая никакого сопротивления.
Когда правила типов становятся несносными
Цель правил типов, введенных вместе с наследованием, в достижении статически проверяемого динамического поведения, так чтобы система, прошедшая проверку при компиляции, не выполняла неадекватных операций над объектами во время выполнения.
