Основы объектно-ориентированного программирования
Шрифт:
При дублируемом наследовании судьбой компонентов должны управлять точно определенные правила, позволяющие разработчикам выбирать для каждого такого компонента разделение, либо дублирование.
Ограниченная универсальность (Constrained genericity)
Сочетание универсальности и наследования дает полезную технику - ограниченную универсальность (constrained genericity). Теперь вы можете определить класс с родовым параметром, представляющим не произвольный тип, а лишь тип, являющийся потомком некоторого класса.
Родовой
Механизм универсальности должен поддерживать форму ограниченной универсальности.
Переопределение (redefinition)
Когда класс является наследником другого класса, может потребоваться изменить реализацию или другие свойства некоторых наследованных компонент. Класс SESSION, управляющий сеансами пользователей в операционной системе, может иметь компонент terminate, выполняющий чистку в конце сеанса. Его наследником может быть класс REMOTE_SESSION, управляющий сеансом удаленного компьютера в сети.
Если завершение удаленного сеанса требует дополнительных действий, таких как, например, уведомление удаленного компьютера, класс REMOTE_SESSION переопределит компонент terminate.
Переопределение может повлиять на реализацию компонента, его сигнатуру (тип аргументов и результата) и спецификацию.
Должно быть возможным переопределить спецификацию, сигнатуру и реализацию наследованного компонента.
Полиморфизм
При наследовании, требование статической типизации, о котором говорилось выше, становится ограничивающим, если бы оно означало, что каждая сущность типа C может быть связана только с объектом точно такого же типа С. Например в системе управления навигацией сущность типа BOAT нельзя было бы использовать для объектов класса MERCHANT_SHIP или SPORTS_BOAT, хотя оба класса являются потомками класса BOAT.
Как уже отмечалось, "сущность" - это имя, к которому во время выполнения могут присоединяться различные значения. Сущность - это обобщение традиционного понятия переменной. |
Полиморфизм (polymorphism) - способность
Должна иметься возможность в период выполнения присоединять к сущности объекты различных возможных типов под управлением наследования.
Динамическое связывание
Сочетание последних двух механизмов, переопределения и полиморфизма, непосредственно предполагает следующий механизм. Допустим, есть вызов, целью которого является полиморфная сущность, например сущность типа BOAT вызывает компонент turn. Различные потомки класса BOAT, возможно, переопределили этот компонент различными способами. Ясно, что должен существовать автоматический механизм, гарантирующий, что версия turn всегда соответствует фактическому типу объекта, вне зависимости от того, как объявлена сущность. Эта возможность называется динамическим связыванием (dynamic binding).
Вызов сущностью компонента всегда должен запускать тот компонент, который соответствует типу присоединенного объекта, а не типу сущности.
При различных выполнениях одного и того же вызова могут запускаться разные компоненты.
Динамическое связывание оказывает большое влияние на структуру ОО-приложения, поскольку дает возможность разработчикам писать простые вызовы, например объект my_boat вызывает компонент turn. В действительности, данный вызов означает несколько возможных вызовов, зависящих от соответствующих ситуаций времени выполнения. Это упраздняет необходимость многих повторных проверок (является ли объект merchant_ship? Является ли он sports_boat?), наводняющих программные продукты, создаваемые при обычных подходах.
Выяснение типа объекта в период выполнения
Разработчики ОО-ПО вскоре вырабатывают здоровую неприязнь к любому стилю вычислений, основанному на явном выборе между различными типами объекта. Полиморфизм и динамическое связывание намного предпочтительнее. Однако в некоторых случаях объект приходит извне, так что автор ПО не имеет возможности с определенностью предсказать его тип. В частности, это случается, если объект извлекается из внешних хранилищ, получен по сети или передан некоторой другой системой.
Тогда ПО нуждается в механизме, обеспечивающем безопасный способ доступа к объекту без нарушения ограничений статической типизации. Такой механизм должен проектироваться с большой аккуратностью, так чтобы не утратить пользы от полиморфизма и динамического связывания.
Операция попытка присваивания (assignment attempt) удовлетворяет этим требованиям. Это условная операция: она пытается присоединить объект к сущности; если при выполнении операции тип объекта соответствует типу сущности, то она действует как нормальное присваивание; в противном случае сущность получает специальное значение void. Итак, можно управлять объектами, тип которых не известен наверняка, не нарушая безопасности системы типов.