2.1.3 Отношения между классами
Моделирование только классов сводит описание системы к отдельным частям без соединений между ними. Чтобы учесть это, в UML есть разные виды связей между классами, такие как Зависимость, Ассоциация, Агрегация, Композиция и Обобщение. Написанное с помощью UML может интерпретироваться как авторами модели, так и ее пользователями. Особенно в случае видов связей часто неясно, какой вид отношений подходит лучше всех. Поэтому важно убедиться, что пользователи и авторы модели одинаково понимают, что подразумевается под каждым из использованных видов связей.
Ассоциация
Ассоциация - семантический вид связи между типизированными экземплярами [96]. Таким образом, у ассоциации есть как минимум два конца. Она происходит между двумя классами, которые являются источником и приемником ассоциации, а также равными участниками этой ассоциации. Источник и приемник ассоциации также могут совпадать. Назначение ассоциации – отобразить долговременную связь.
Графически ассоциации показываются сплошными линиями между задействованными классами. Для указания возможности навигации между объектами ассоциации линии могут иметь стрелки на каждом из концов, показывающие возможные направления ассоциации. На практике стрелки в обе стороны для указания двунаправленности ассоциации не рисуют, так как она является таковой в большинстве случаев. Зная это, невозможно отличить ненаправленную ассоциацию (нет стрелок) от двунаправленной (нет стрелок). В этом случае можно поставить «Х» на конце, в направлении которого ассоциация не идёт, чтобы явно указать на это.
Ассоциации также могут иметь имена, обычно включающие в себя глаголы, которые описывают отношения между участвующими типами более подробно. Эта информация обычно используется только для облегчения понимания модели, и не оказывает никакого влияния на её внедрение. К тому же, рядом с именем может стоять маленький закрашенный треугольник, показывающий, в каком направлении правильно читать имя ассоциации с учётом ассоциированных типов. Этот индикатор не влияет на направленность, как можно было бы предположить, а служит только для помощи пользователю модели. Более того, каждый конец ассоциации может иметь ролевое имя, которое описывает роль участвующих классов в их отношениях. Эти имена являются свойствами отношения или участвующих в нём классов, и их видимость, как и у атрибутов, также может быть ограничена при помощи использовании символов ‘+’, ‘-’, ‘#’ и ‘~’. Роли – это свойства классов, и они обычно реализованы как атрибуты соответствующих классов (есть исключения, которые невозможно подробно объяснить в рамках этой главы, смотри [96]). Таким образом, это альтернативный способ задать атрибут комплексным типом – выбрать нужный должен автор модели.
Для ограничения числа экземпляров этого взаимодействия, кратности могут быть заданы для каждого конца отношения. Задание кратности осуществляется аналогично заданию кратности для атрибутов (смотри раздел 2.1.2.1), за исключением того, что они не заключаются в скобки. Если явно не задать кратность, то ее значение по умолчанию будет равно 1.
Рисунок 2.4 показывает большинство этих свойств:
Рис. 2.4. Ассоциации в UML
У класса «Трансформатор» (Transformer) есть направленная ассоциация с классом «Ветрогенератор» (WindEnergyPlant) под названием «преобразует электричество» (transforms power). У класса «Ветрогенератор» есть ассоциация с «Генератором» (Generator), у которого есть видимая всем роль «генератор» и который может иметь от одного до бесконечного числа генераторов. С другой стороны, у «Генератора» есть ровно одна ассоциация с «Ветрогенератором», у которого есть видимая всем роль «ветрогенератор».
Ассоциации могут иметь дополнительные свойства, могут быть использованы с другими элементами модели, могут быть установлены между более чем двумя классами, и т.д. Но так как это не является темой книги, эти возможности не будут описаны более подробно; при необходимости о них можно прочитать в, например, [96] или [99]. Другой тип отношений, агрегация, будет описан в следующем разделе.
Агрегация
Более сильный вид ассоциации – агрегация, которая является бинарной ассоциацией. Агрегация и композиция (смотри следующий раздел) - наверное, два наиболее обсуждаемых вида ассоциации, и их применение может отличаться у разных разработчиков моделей.
Агрегация представляет собой общую ассоциацию, в которой выделяют один из концов ассоциации, который много использует или сильно зависит от другого конца. Часто агрегацию описывают как отношение «часть целого-целое», которое существует между задействованными классами. Важным свойством этого отношения, которое надо подчеркнуть, является то, что обе части могут существовать друг без друга. Такое отношение может быть описано как «владение», подразумевая, что одна сторона принадлежит другой.
Конечно, агрегации можно объяснить более подробно, как видно на примере ассоциаций. Агрегации изображают незакрашенным ромбом на одном из концов сплошных линий ассоциации. Положение символа агрегации определяет сторону, «владеющую» другой стороной – как показано на верхней части рисунка 2.5. Пример агрегации на этом рисунке показывает, что ветрогенератор «владеет» ротором.
Рис. 2.5. Различные виды ассоциаций: агрегация и композиция
Композиция
Еще более сильные ассоциации между двумя классами могут быть представлены композитными ассоциациями – так называемыми композициями. Композиция – это другой вид агрегации, который также выделяет одну из сторон отношения, и который может быть объяснён как отношение «целое-часть». В отличие от агрегации, время жизни «частей» композита напрямую связаны с экземплярами, которые более или менее «включены» в этот тип ассоциации. Если удаляют композит, все его части обычно также удаляются вместе с ним.
Более того, это подразумевает, что «части», включенные в композицию, могут быть включены только в одну композитную ассоциацию в любой момент времени. Композиции можно объяснить более подробно с использованием известных сведений об ассоциациях.
Графическим отображением композиции является закрашенный ромб на конце линии ассоциации, принадлежащем классу-композиту. Пример можно найти на рисунке 2.5. Башня является частью ветрогенератора, который не может существовать без неё.
Зависимость
Зависимость – это отношение между как минимум одним элементом-источником и как минимум одним элементом-приемником. Она представляет собой более слабое отношение, чем ассоциация, и ее описывают как «один или несколько элементов модели требуют других элементов модели для их определения или создания» [96]. Это означает, например, что зависимый класс кратковременно взаимодействует с независимыми классами. Зависимость может проявляться по-разному, например, в виде использования, исполнения или абстракции.
Что касается реализации, для зависимости будут устанавливаться только преходящие отношения, то есть отношения, не длящиеся какой-то длительный период времени. Зависимости показываются пунктирной линией между классами, заканчивающейся стрелкой, которая указывает на независимый класс. На рисунке 2.6 приведён пример, который показывает, что ветрогенератор зависит от технического обслуживания. В UML есть возможность указать тип зависимости более подробно. Для этого используется механизм, который называется «стереотипы», и в нём есть несколько встроенных типов зависимостей, такие как, например «вызвать», «исполнить», «создать экземпляр» или «использовать».
Концепция зависимостей может быть, как и ассоциации, использована с другими элементами, не только классами – более подробно можно найти в [95] или [96].
Рис. 2.6 Отношение зависимости в UML
Обобщение
В то время как все предыдущие типы отношений были довольно похожи, в обобщении в дело вступает другой аспект. Обобщение – это отношение между более общим элементом и его более специализированной версией. Оно может быть наилучшим образом объяснено словами «является экземпляром». Этот тип отношений может быть использован, чтобы иерархически структурировать классы для выявления схожестей в более общих классах и специализирования их в производных классах. Идея, иллюстрируемая обобщением, в объектно-ориентированных языках программирования называется наследование.
Это означает, что каждый класс, который происходит от класса (например, при специализировании более общего класса) наследует все его особенности, которые обязательно включают атрибуты, операции и отношения, и может дальше расширять класс своими собственными особенностями, или переопределять унаследованные особенности, чтобы они стали более специализированными.
Другие классы могут затем снова унаследовать от этих специализированных классов. Возможно также, что один класс имеет больше одного отношения обобщения, и наследует все особенности от всех классов, с которыми связан. Эта концепция называется множественное наследование. Изначально оно не поддерживается во всех современных языках программирования. Отношение обобщения – единственная возможность создать подкласс от абстрактных классов для того, чтобы они могли создать свой экземпляр. Обобщения изображаются сплошной линией от одного класса к другому, которая заканчивается незакрашенным треугольником на стороне более общего класса (смотри рисунок 2.7).
Рис. 2.7. Реализация наследования через отношение обобщения в UML
Несколько классов и другие элементы модели могут быть логически сгруппированы в пакеты, чтобы вся модель оставалась удобной в обращении и более доступной. Другой тип диаграмм – диаграммы пакетов – в дальнейшем используются для просмотра структуры всей модели в целом. Они кратко описаны в следующем разделе.
