Шаг 26.
Унифицированный язык моделирования UML.
Иерархия. Множественное наследование

    На этом шаге рассмотрим пример множественного наследования.

    В предыдущем примере продемонстрировано одиночное наследование: подкласс ПЛАН ВЫРАЩИВАНИЯ_ФРУКТОВ (FruitGrowingPlan) имел только один суперкласс ПЛАН ВЫРАЩИВАНИЯ_РАСТЕНИЙ (GrowingPlan). Иногда полезно реализовать наследование от нескольких суперклассов.

    Предположим, например, что требуется определить класс, представляющий разновидности растений. Анализ предметной области показывает, что цветы, фрукты и овощи имеют свои особые свойства, существенные для технологии их выращивания. Например, для абстракции цветов важно знать периоды цветения и созревания семян. Аналогично, для абстракций фруктов и овощей важен момент сбора урожая. Исходя из этих соображений, можно создать два новых класса — ЦВЕТОК (Flower) и ПЛОДОНОСЯЩЕЕ_РАСТЕНИЕ(FruitVegetable) — наследники суперкласса РАСТЕНИЕ (Plant). Какую же модель следует выбрать, если растение и цветет, и плодоносит? Например, флористы часто используют для составления букетов цветки яблони, вишни и сливы. Для этой абстракции придется создать третий класс ЦВЕТУЩЕЕ_ПЛОДОНОСЯЩЕЕ_РАСТЕНИЕ (FlowerFruitVegetable) — наследник классов ЦВЕТОК (Flower) и ПЛАН ВЫРАЩИВНИЯ_ПЛОДОНОСЯЩИХ_РАСТЕНИЙ (FruitVegetablePlant).

    Чтобы наилучшим образом выразить новую абстракцию и не допустить ошибку, следует создать классы, независимо друг от друга описывающие уникальные свойства цветов, а также фруктов и овощей соответственно. Эти два класса не имеют суперкласса. Они называются классами-примесями, поскольку смешиваются вместе с другими классами, создавая новые подклассы. Например, можно описать класс РОЗА (Rose) рис. 1, наследующий свойства классов РАСТЕНИЯ (Plant) и ЦВЕТОК (Flower). Таким образом, экземпляры подкласса РОЗА (Rose) наследуют структуру и поведение классов РАСТЕНИЕ (Plant) и ЦВЕТОК (Flower).


Рис.1. Класс Rose — наследник нескольких суперклассов

    Точно так же можно определить класс МОРКОВЬ (Carrot), продемонстрированный на рис. 2.


Рис.2. Класс Carrot — наследник нескольких суперклассов

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


Рис.3. Класс Carrot — наследник нескольких суперклассов

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


Рис.4. Повторное наследование

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

    Множественным наследованием часто злоупотребляют. Например, сладкая вата — это разновидность сладости, но никак не ваты. К этой ситуации можно применить описанный ранее критерий: если класс В не является разновидностью класса А, то он не должен быть наследником класса А. Часто плохо продуманные структуры множественного наследования следует свести к одному суперклассу, по возможности используя агрегацию других классов подклассами.

    На следующем шаге рассмотрим пример агрегации.




Предыдущий шаг Содержание Следующий шаг