Наследование реализации

Наследование интерфейса

Углубленное моделирование обобщения и наследования

Существует три основных вида отношений между классами: ассоциация, агрегация и обобщение. Понятия обобщения и наследования связаны, но не идентичны.

Обобщение - это семантическое отношение между классами. Оно устанавливает, что интерфейс подкласса должен включать все (открытые и защищенные) свойства суперкласса (т. е. наследуется интерфейс).

Наследование - это “механизм, с помощью которого более специфические элементы вбирают в себя структуру и поведение, определенные более общими элементами” (в том числе наследуется реализация).

Когда обобщение используется с целью обеспечения подстановки, оно может служить синонимом понятия наследование интерфейса. При этом производный класс наследует типы атрибутов и сигнатуру операций (имя операции плюс формальные аргументы) (рис. 5.7.). Говорят, что производный класс поддерживает интерфейс суперкласса. Реализация унаследованных операций откладывается на более позднее время.

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

 

Рисунок 5.7. Использование отношения реализации для представления наследования интерфейса

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

Замещение (overriding) может означать включение (вызов) метода суперкласса в метод подкласса и расширение его за счет введения новых функциональных возможностей. Оно также может означать полную замену метода суперкласса методом подкласса. Наследование реализации допускает совместное использование описаний свойства, повторное использование программного кода и полиморфизм.

Единственным правильным способом использования наследования является наращиваемое определение класса. Производный класс обладает большим количеством свойств (атрибутов и/или методов), чем его базовый класс. Подобное наследование известно также как наследование посредством расширения или расширяющее наследование (extension inheritance).

 

Рисунок 5.8. Расширяющее наследование

Производный класс Employee (Сотрудник) расширяет базовый класс Person (Личность). Класс Person на рис. 5.8 не является абстрактным классом. Могут существовать некоторые объекты Person, которые представляют просто некую личность (в том смысле, что они не являются сотрудниками, т.е. объектами класса Employee).

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

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

Основные факторы риска связаны со следующими перечисленными ниже проблемами:

● Изменчивость базового класса.

● Замещение и обратные вызовы.

● Множественное наследование реализации.

Проблема изменчивости базового класса (суперкласса) касается ситуации, при которой производные классы уже разработаны, в то время как реализация их суперкласса (или суперклассов при множественном наследовании) продолжается. Это серьезная проблема в любом случае, а в особенности в ситуации, когда суперкласс можно получить из внешних источников, находящихся вне контроля бригады разработчиков системы.

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

1 Подкласс может наследовать интерфейс и реализацию метода без внесения каких-либо изменений в реализацию.

2 Подкласс может наследовать код и включить его (вызвать его) в свой собственный метод с той же сигнатурой.

3 Подкласс может наследовать код и затем полностью заместить его новой реализацией с той же сигнатурой.

4 Подкласс может наследовать пустой код (т.е. декларация метода отсутствует), а затем ввести реализацию для метода.

5 Подкласс может наследовать только интерфейс метода (т.е. мы имеем случай наследования интерфейса), а затем ввести реализацию для метода.

Из этих пяти методов первые два доставляют наибольшие трудности.

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