Важно вернуться к основам: открытое наследование должно всегда моделировать обобщение, т.е. производный класс должен быть уточнением базового класса, чего не скажешь о приведенном выше примере. Если требуется смоделировать отношение "иметь" (например, автомобиль имеет руль), то это делается с помощью агрегирования (рис. 18.15).
Диаграмма на рис. 18.15 показывает, что автомобиль имеет руль, четыре колеса и от двух до пяти дверей. Это более точная модель отношения автомобиля и его частей. Обратите внимание, что ромбик на диаграмме не закрашен. Это потому, что отношение моделируется с помощью агрегирования, а не композиции. Композиция подразумевает контроль за временем жизни объекта вложенного класса. Хотя автомобиль имеет шины и дверь, но они могут существовать и до того, как станут частями автомобиля, и после того, как перестанут ими быть.
Рис. 18.15. Модель агрегирования
На рис. 18.16 показана модель композиции. Эта модель сообщает нам, что класс "тело" не только включает в себя (что можно было бы реализовать агрегированием) голову, две руки и две ноги, но что эти объекты (голова, руки и ноги) будут созданы при создании тела и исчезнут вместе с ним. Иными словами, они не имеют независимого существования.
Рис. 18.16. Модель композиции
Дискриминаторы и силовые классы
Как можно спроектировать производство разных моделей автомобилей одной марки? Предположим, вас наняла фирма Acme Motors, которая производит пять автомобилей: Pluto (компактный малолитражный автомобиль для поездок за покупками), Venus (четырехдверный "седан" с двигателем средней мощности), Mars (спортивный автомобиль типа "купе" с наиболее мощным двигателем, рассчитанный на максимальную скорость), Jupiter (мини-фургон с форсированным двигателем как у спортивного купе, правда, менее скоростной, зато более мощный) и Earth (маломощный, но скоростной фургон).
Можно было бы просто произвести все эти модели от общего класса Car, как показано на рис. 18.17.
Рис. 18.17. Обобщение подклассов всех моделей в общий базовый класс
Но давайте более детально проанализируем различия между моделями. Очевидно, что они различаются мощностью двигателя, типами кузова и специализацией. Комбинируя эти основные признаки, мы получим характеристики различных моделей. Таким образом, в нашем примере важнее сконцентрировать внимание не на названиях моделей, а на их основных признаках. Такие признаки называются дискриминаторами и в UML отображаются особым образом (см. рис. 18.17).
Рис. 18.18. Модель отношения дискриминаторов
Диаграмма на рис. 18.18 показывает, что классы разных моделей можно производить от класса Автомобиль, комбинируя такие дискриминаторы, как мощность двигателя, тип кузова и назначение автомобиля.
Каждый дискриминатор можно реализовать в виде простого перечисления. Например, объявим перечисление типов кузова:
enum BodyType={sedan, coupe, minivan, stationwagon}
Однако далеко не каждый дискриминатора можно объявить, просто назвав его. Например, назначение определяется многими параметрами. В таком случае дискриминатор можно смоделировать как класс, и разные типы дискриминатора будут возвращаться как объекты класса.
Таким образом, технические характеристики автомобиля, определяющие его использование, могут быть представлены объектом типа performance, содержащим данные о скорости, габаритах и прочих характеристиках. В UML классы, в которых инкапсулирован дискриминатор и которые используются для создания экземпляров другого класса (в нашем примере класса Автомобиль) таким образом, что разные экземпляры класса приобретают характеристики разных типов (например, Спортивный автомобиль и Семейный автомобиль), называются силовыми. В нашем примере класс Назначение (performance) является силовым для класса Автомобиль. При создании объекта класса Автомобиль также создается объект Назначение, который ассоциируется с текущим объектом Автомобиль, как показано на рис. 18.19.
Использование силовых классов позволяет создавать различные логические типы, не прибегая к наследованию. Поэтому в программе можно легко манипулировать множеством типов, не создавая класс для каждого нового типа.
Читать дальше